* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
static char sccsid
[] = "@(#)lpr.c 5.2 (Berkeley) 11/17/85";
* Allows multiple printers and printers on remote machines by
* using information from a printer data base.
char *tfname
; /* tmp copy of cf before linking */
char *cfname
; /* daemon control files, linked from tf's */
char *dfname
; /* data files */
int nact
; /* number of jobs to act on */
int tfd
; /* control file descriptor */
int mailflg
; /* send mail */
int qflag
; /* q job, but don't exec daemon */
char format
= 'f'; /* format char for printing files */
int rflag
; /* remove files upon completion */
int sflag
; /* symbolic link flag */
int inchar
; /* location to increment char in file names */
int ncopies
= 1; /* # of copies to make */
int iflag
; /* indentation wanted */
int indent
; /* amount to indent */
int hdr
= 1; /* print header or not (default is yes) */
int userid
; /* user id */
char *person
; /* user name */
char *title
; /* pr'ing title */
char *fonts
[4]; /* troff font names */
char *width
; /* width for versatec printing */
char host
[32]; /* host name */
char *class = host
; /* class title on header page */
char *jobname
; /* job name on header page */
char *name
; /* program name */
char *printer
; /* printer name */
int MX
; /* maximum number of blocks to copy */
int MC
; /* maximum number of copies allowed */
int DU
; /* daemon user-id */
char *SD
; /* spool directory */
char *LO
; /* lock file name */
char *RG
; /* restrict group */
short SC
; /* suppress multiple copies */
extern struct passwd
*getpwuid();
if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
if (signal(SIGQUIT
, SIG_IGN
) != SIG_IGN
)
signal(SIGQUIT
, cleanup
);
if (signal(SIGTERM
, SIG_IGN
) != SIG_IGN
)
signal(SIGTERM
, cleanup
);
gethostname(host
, sizeof (host
));
openlog("lpd", 0, LOG_LPR
);
while (argc
> 1 && argv
[1][0] == '-') {
case 'P': /* specifiy printer name */
case 'C': /* classification spec */
case 'T': /* pr's title line */
case 'l': /* literal output */
case 'p': /* print using ``pr'' */
case 't': /* print troff output (cat files) */
case 'n': /* print ditroff output */
case 'd': /* print tex output (dvi files) */
case 'g': /* print graph(1G) output */
case 'c': /* print cifplot output */
case 'v': /* print vplot output */
case 'f': /* print fortran output */
case '4': /* troff fonts */
fonts
[arg
[1] - '1'] = *++argv
;
case 'w': /* versatec page width */
case 'r': /* remove file when done */
case 'm': /* send mail when done */
case 'h': /* toggle want of header page */
case 's': /* try to link files */
case 'q': /* just q job */
case 'i': /* indent output */
indent
= arg
[2] ? atoi(&arg
[2]) : 8;
if (printer
== NULL
&& (printer
= getenv("PRINTER")) == NULL
)
fatal("multiple copies are not allowed");
if (MC
> 0 && ncopies
> MC
)
fatal("only %d copies are allowed", MC
);
* Get the identity of the person doing the lpr using the same
if ((pw
= getpwuid(userid
)) == NULL
)
* Check for restricted group access.
if ((gptr
= getgrnam(RG
)) == NULL
)
fatal("Restricted group specified incorrectly");
if (gptr
->gr_gid
!= getgid()) {
while (*gptr
->gr_mem
!= NULL
) {
if ((strcmp(person
, *gptr
->gr_mem
)) == 0)
if (*gptr
->gr_mem
== NULL
)
fatal("Not a member of the restricted group");
* Check to make sure queuing is enabled if userid is not root.
(void) sprintf(buf
, "%s/%s", SD
, LO
);
if (userid
&& stat(buf
, &stb
) == 0 && (stb
.st_mode
& 010))
fatal("Printer queue is disabled");
* Initialize the control file.
(void) fchown(tfd
, DU
, -1); /* owned by daemon for protection */
jobname
= (arg
= rindex(argv
[1], '/')) ? arg
+1 : argv
[1];
if (format
== 't' || format
== 'n' || format
== 'd')
* Read the files and spool them.
if ((f
= test(arg
= *++argv
)) < 0)
continue; /* file unreasonable */
if (sflag
&& (cp
= linked(arg
)) != NULL
) {
(void) sprintf(buf
, "%d %d", statb
.st_dev
, statb
.st_ino
);
card('T', title
? title
: arg
);
for (i
= 0; i
< ncopies
; i
++)
card(format
, &dfname
[inchar
-2]);
card('U', &dfname
[inchar
-2]);
printf("%s: %s: not linked, copying instead\n", name
, arg
);
if ((i
= open(arg
, O_RDONLY
)) < 0) {
printf("%s: cannot open %s\n", name
, arg
);
if (f
&& unlink(arg
) < 0)
printf("%s: %s: not removed\n", name
, arg
);
* Touch the control file to fix position in the queue.
if ((tfd
= open(tfname
, O_RDWR
)) >= 0) {
if (read(tfd
, &c
, 1) == 1 && lseek(tfd
, 0L, 0) == 0 &&
write(tfd
, &c
, 1) != 1) {
printf("%s: cannot touch %s\n", name
, tfname
);
if (link(tfname
, cfname
) < 0) {
printf("%s: cannot rename %s\n", name
, cfname
);
if (qflag
) /* just q things up */
if (!startdaemon(printer
))
printf("jobs queued, but cannot start daemon.\n");
* Create the file n and copy from file descriptor f.
register int fd
, i
, nr
, nc
;
card('T', title
? title
: n
);
for (i
= 0; i
< ncopies
; i
++)
card(format
, &dfname
[inchar
-2]);
card('U', &dfname
[inchar
-2]);
while ((i
= read(f
, buf
, BUFSIZ
)) > 0) {
if (write(fd
, buf
, i
) != i
) {
printf("%s: %s: temp file write error\n", name
, n
);
printf("%s: %s: copy file is too large\n", name
, n
);
printf("%s: %s: empty input file\n", name
, f
? n
: "stdin");
* Try and link the file to dfname. Return a pointer to the full
* path name if successful.
if ((cp
= rindex(buf
, '/')) != NULL
)
return(symlink(file
, dfname
) ? NULL
: file
);
* Put a line into the control file.
while ((c
= *p2
++) != '\0') {
* Create a new file in the spool directory.
int oldumask
= umask(0); /* should block signals */
printf("%s: cannot create %s\n", name
, n
);
if (fchown(f
, userid
, -1) < 0) {
printf("%s: cannot chown %s\n", name
, n
);
if (++n
[inchar
-2] == 't') {
printf("too many files - break up the job\n");
} else if (n
[inchar
] == '[')
* Cleanup after interrupts and errors.
signal(SIGQUIT
, SIG_IGN
);
signal(SIGTERM
, SIG_IGN
);
while (tfname
[i
]-- != 'A');
while (cfname
[i
]-- != 'A');
while (dfname
[i
]-- != 'A');
} while (dfname
[i
-2]-- != 'd');
* Test to see if this is a printable file.
* Return -1 if it is not, 0 if its printable, and 1 if
* we should remove it after printing.
if (access(file
, 4) < 0) {
printf("%s: cannot access %s\n", name
, file
);
if (stat(file
, &statb
) < 0) {
printf("%s: cannot stat %s\n", name
, file
);
if ((statb
.st_mode
& S_IFMT
) == S_IFDIR
) {
printf("%s: %s is a directory\n", name
, file
);
if (statb
.st_size
== 0) {
printf("%s: %s is an empty file\n", name
, file
);
if ((fd
= open(file
, O_RDONLY
)) < 0) {
printf("%s: cannot open %s\n", name
, file
);
if (read(fd
, &execb
, sizeof(execb
)) == sizeof(execb
))
printf("%s: %s is an executable program", name
, file
);
printf("%s: %s is an archive file", name
, file
);
if ((cp
= rindex(file
, '/')) == NULL
) {
printf("%s: %s: is not removable by you\n", name
, file
);
printf(" and is unprintable\n");
* itoa - integer to string conversion
static char b
[10] = "########";
* Perform lookup for printer name or abbreviation --
static char pbuf
[BUFSIZ
/2];
if ((status
= pgetent(buf
, s
)) < 0)
fatal("cannot open printer description file");
fatal("%s: unknown printer", s
);
if ((SD
= pgetstr("sd", &bp
)) == NULL
)
if ((LO
= pgetstr("lo", &bp
)) == NULL
)
if ((MX
= pgetnum("mx")) < 0)
if ((MC
= pgetnum("mc")) < 0)
if ((DU
= pgetnum("du")) < 0)
register int c
, len
, fd
, n
;
(void) sprintf(buf
, "%s/.seq", SD
);
if ((fd
= open(buf
, O_RDWR
|O_CREAT
, 0661)) < 0) {
printf("%s: cannot create %s\n", name
, buf
);
if (flock(fd
, LOCK_EX
)) {
printf("%s: cannot lock %s\n", name
, buf
);
if ((len
= read(fd
, buf
, sizeof(buf
))) > 0) {
for (cp
= buf
; len
--; ) {
if (*cp
< '0' || *cp
> '9')
n
= n
* 10 + (*cp
++ - '0');
len
= strlen(SD
) + strlen(host
) + 8;
tfname
= mktemp("tf", n
, len
);
cfname
= mktemp("cf", n
, len
);
dfname
= mktemp("df", n
, len
);
sprintf(buf
, "%03d\n", n
);
(void) write(fd
, buf
, strlen(buf
));
(void) close(fd
); /* unlocks as well */
if ((s
= malloc(len
)) == NULL
)
(void) sprintf(s
, "%s/%sA%03d%s", SD
, id
, num
, host
);