1
/* $OpenBSD: lpr.c,v 1.19 1997/07/25 20:12:13 mickey Exp $ */
2
/* $NetBSD: lpr.c,v 1.10 1996/03/21 18:12:25 jtc Exp $ */
5
* Copyright (c) 1983, 1989, 1993
6
* The Regents of the University of California. All rights reserved.
7
* (c) UNIX System Laboratories, Inc.
8
* All or some portions of this file are derived from material licensed
9
* to the University of California by American Telephone and Telegraph
10
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
11
* the permission of UNIX System Laboratories, Inc.
14
* Redistribution and use in source and binary forms, with or without
15
* modification, are permitted provided that the following conditions
17
* 1. Redistributions of source code must retain the above copyright
18
* notice, this list of conditions and the following disclaimer.
19
* 2. Redistributions in binary form must reproduce the above copyright
20
* notice, this list of conditions and the following disclaimer in the
21
* documentation and/or other materials provided with the distribution.
22
* 3. All advertising materials mentioning features or use of this software
23
* must display the following acknowledgement:
24
* This product includes software developed by the University of
25
* California, Berkeley and its contributors.
26
* 4. Neither the name of the University nor the names of its contributors
27
* may be used to endorse or promote products derived from this software
28
* without specific prior written permission.
30
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44
static char copyright[] =
45
"@(#) Copyright (c) 1983, 1989, 1993\n\
46
The Regents of the University of California. All rights reserved.\n";
51
static char sccsid[] = "@(#)lpr.c 8.4 (Berkeley) 4/28/95";
53
static char rcsid[] = "$OpenBSD: lpr.c,v 1.19 1997/07/25 20:12:13 mickey Exp $";
58
* lpr -- off line print
60
* Allows multiple printers and printers on remote machines by
61
* using information from a printer data base.
64
#include <sys/param.h>
82
#include "pathnames.h"
84
static char *cfname; /* daemon control files, linked from tf's */
85
static char *class = host; /* class title on header page */
86
static char *dfname; /* data files */
87
static char *fonts[4]; /* troff font names */
88
static char format = 'f'; /* format char for printing files */
89
static int hdr = 1; /* print header or not (default is yes) */
90
static int iflag; /* indentation wanted */
91
static int inchar; /* location to increment char in file names */
92
static int indent; /* amount to indent */
93
static char *jobname; /* job name on header page */
94
static int mailflg; /* send mail */
95
static int nact; /* number of jobs to act on */
96
static int ncopies = 1; /* # of copies to make */
97
static char *person; /* user name */
98
static int qflag; /* q job, but don't exec daemon */
99
static int rflag; /* remove files upon completion */
100
static int sflag; /* symbolic link flag */
101
static int tfd; /* control file descriptor */
102
static char *tfname; /* tmp copy of cf before linking */
103
static char *title; /* pr'ing title */
104
static int userid; /* user id */
105
static char *width; /* width for versatec printing */
107
static struct stat statb;
109
static void card __P((int, char *));
110
static void chkprinter __P((char *));
111
static void cleanup __P((int));
112
static void copy __P((int, char []));
113
static void fatal2 __P((const char *, ...));
114
static char *linked __P((char *));
115
static char *lmktemp __P((char *, int, int));
116
static void mktemps __P((void));
117
static int nfile __P((char *));
118
static int test __P((char *));
119
static char *itoa __P((int));
130
register char *arg, *cp;
138
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
139
signal(SIGHUP, cleanup);
140
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
141
signal(SIGINT, cleanup);
142
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
143
signal(SIGQUIT, cleanup);
144
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
145
signal(SIGTERM, cleanup);
148
gethostname(host, sizeof (host));
149
openlog("lpd", 0, LOG_LPR);
151
while (argc > 1 && argv[1][0] == '-') {
156
case 'P': /* specifiy printer name */
165
case 'C': /* classification spec */
175
case 'U': /* user name */
185
case 'J': /* job name */
195
case 'T': /* pr's title line */
204
case 'l': /* literal output */
205
case 'p': /* print using ``pr'' */
206
case 't': /* print troff output (cat files) */
207
case 'n': /* print ditroff output */
208
case 'd': /* print tex output (dvi files) */
209
case 'g': /* print graph(1G) output */
210
case 'c': /* print cifplot output */
211
case 'v': /* print vplot output */
215
case 'f': /* print fortran output */
219
case '4': /* troff fonts */
225
fonts[arg[1] - '1'] = *++argv;
229
case 'w': /* versatec page width */
233
case 'r': /* remove file when done */
237
case 'm': /* send mail when done */
241
case 'h': /* toggle want of header page */
245
case 's': /* try to link files */
249
case 'q': /* just q job */
253
case 'i': /* indent output */
255
indent = arg[2] ? atoi(&arg[2]) : 8;
258
case '#': /* n copies */
259
if (isdigit(arg[2])) {
267
if (printer == NULL) {
271
if ((p = getenv("PRINTER")) != NULL)
275
if (SC && ncopies > 1)
276
fatal2("multiple copies are not allowed");
277
if (MC > 0 && ncopies > MC)
278
fatal2("only %d copies are allowed", MC);
280
* Get the identity of the person doing the lpr using the same
284
if (userid != DU || person == 0) {
285
if ((pw = getpwuid(userid)) == NULL)
286
fatal2("Who are you?");
287
person = pw->pw_name;
290
* Check for restricted group access.
292
if (RG != NULL && userid != DU) {
293
if ((gptr = getgrnam(RG)) == NULL)
294
fatal2("Restricted group specified incorrectly");
295
if (gptr->gr_gid != getgid()) {
296
while (*gptr->gr_mem != NULL) {
297
if ((strcmp(person, *gptr->gr_mem)) == 0)
301
if (*gptr->gr_mem == NULL)
302
fatal2("Not a member of the restricted group");
306
* Check to make sure queuing is enabled if userid is not root.
308
(void) snprintf(buf, sizeof(buf), "%s/%s", SD, LO);
309
if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
310
fatal2("Printer queue is disabled");
312
* Initialize the control file.
317
(void) fchown(tfd, DU, -1); /* owned by daemon for protection */
322
if (jobname == NULL) {
326
jobname = (arg = strrchr(argv[1], '/')) ? arg+1 : argv[1];
333
card('I', itoa(indent));
336
if (format == 't' || format == 'n' || format == 'd')
337
for (i = 0; i < 4; i++)
338
if (fonts[i] != NULL)
339
card('1'+i, fonts[i]);
344
* Read the files and spool them.
348
else while (--argc) {
349
if ((f = test(arg = *++argv)) < 0)
350
continue; /* file unreasonable */
352
if (sflag && (cp = linked(arg)) != NULL) {
353
(void) snprintf(buf, sizeof(buf), "%d %d", statb.st_dev,
357
card('T', title ? title : arg);
358
for (i = 0; i < ncopies; i++)
359
card(format, &dfname[inchar-2]);
360
card('U', &dfname[inchar-2]);
369
printf("%s: %s: not linked, copying instead\n", name, arg);
370
if ((i = open(arg, O_RDONLY)) < 0) {
371
printf("%s: cannot open %s\n", name, arg);
375
if (f && unlink(arg) < 0)
376
printf("%s: %s: not removed\n", name, arg);
384
* Touch the control file to fix position in the queue.
387
if ((tfd = open(tfname, O_RDWR)) >= 0) {
390
if (read(tfd, &c, 1) == 1 &&
391
lseek(tfd, (off_t)0, 0) == 0 &&
392
write(tfd, &c, 1) != 1) {
393
printf("%s: cannot touch %s\n", name, tfname);
399
if (link(tfname, cfname) < 0) {
400
printf("%s: cannot rename %s\n", name, cfname);
406
if (qflag) /* just q things up */
408
if (!startdaemon(printer))
409
printf("jobs queued, but cannot start daemon.\n");
418
* Create the file n and copy from file descriptor f.
425
register int fd, i, nr, nc;
429
card('T', title ? title : n);
430
for (i = 0; i < ncopies; i++)
431
card(format, &dfname[inchar-2]);
432
card('U', &dfname[inchar-2]);
436
while ((i = read(f, buf, BUFSIZ)) > 0) {
437
if (write(fd, buf, i) != i) {
438
printf("%s: %s: temp file write error\n", name, n);
445
if (MX > 0 && nr > MX) {
446
printf("%s: %s: copy file is too large\n",
454
printf("%s: %s: empty input file\n", name, f ? n : "stdin");
460
* Try and link the file to dfname. Return a pointer to the full
461
* path name if successful.
468
static char nfile[MAXPATHLEN];
472
if (getcwd(nfile, sizeof(nfile)) == NULL)
475
while (file[0] == '.') {
481
if (file[2] == '/') {
482
if ((cp = strrchr(nfile, '/')) != NULL)
490
strncat(nfile, "/", sizeof(nfile) - strlen(nfile) - 1);
491
strncat(nfile, file, sizeof(nfile) - strlen(nfile) - 1);
495
ret = symlink(file, dfname);
497
return(ret ? NULL : file);
501
* Put a line into the control file.
509
register char *p1 = buf;
510
register int len = 2;
513
while ((c = *p2++) != '\0' && len < sizeof(buf)) {
514
*p1++ = (c == '\n') ? ' ' : c;
518
write(tfd, buf, len);
522
* Create a new file in the spool directory.
529
int oldumask = umask(0); /* should block signals */
532
f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
533
(void) umask(oldumask);
535
printf("%s: cannot create %s\n", name, n);
538
if (fchown(f, userid, -1) < 0) {
539
printf("%s: cannot chown %s\n", name, n);
540
cleanup(0); /* cleanup does exit */
543
if (++n[inchar] > 'z') {
544
if (++n[inchar-2] == 't') {
545
printf("too many files - break up the job\n");
549
} else if (n[inchar] == '[')
555
* Cleanup after interrupts and errors.
563
signal(SIGHUP, SIG_IGN);
564
signal(SIGINT, SIG_IGN);
565
signal(SIGQUIT, SIG_IGN);
566
signal(SIGTERM, SIG_IGN);
572
while (tfname[i]-- != 'A');
576
while (cfname[i]-- != 'A');
581
while (dfname[i]-- != 'A');
583
} while (dfname[i-2]-- != 'd');
588
* Test to see if this is a printable file.
589
* Return -1 if it is not, 0 if its printable, and 1 if
590
* we should remove it after printing.
600
if ((fd = open(file, O_RDONLY)) < 0) {
601
printf("%s: cannot open %s\n", name, file);
604
if (fstat(fd, &statb) < 0) {
605
printf("%s: cannot stat %s\n", name, file);
608
if ((statb.st_mode & S_IFMT) == S_IFDIR) {
609
printf("%s: %s is a directory\n", name, file);
612
if (statb.st_size == 0) {
613
printf("%s: %s is an empty file\n", name, file);
616
if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
618
printf("%s: %s is an executable program and is unprintable",
625
if ((cp = strrchr(file, '/')) == NULL) {
626
if (access(".", 2) == 0)
633
fd = access(file, 2);
639
printf("%s: %s: is not removable by you\n", name, file);
647
* itoa - integer to string conversion
653
static char b[10] = "########";
664
* Perform lookup for printer name or abbreviation --
672
if ((status = cgetent(&bp, printcapdb, s)) == -2)
673
fatal2("cannot open printer description file");
674
else if (status == -1)
675
fatal2("%s: unknown printer", s);
676
if (cgetstr(bp, "sd", &SD) == -1)
678
if (cgetstr(bp, "lo", &LO) == -1)
680
cgetstr(bp, "rg", &RG);
681
if (cgetnum(bp, "mx", &MX) < 0)
683
if (cgetnum(bp,"mc", &MC) < 0)
685
if (cgetnum(bp, "du", &DU) < 0)
687
SC = (cgetcap(bp, "sc", ':') != NULL);
691
* Make the temp files.
696
register int len, fd, n;
701
(void) snprintf(buf, sizeof(buf), "%s/.seq", SD);
703
if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
704
printf("%s: cannot create %s\n", name, buf);
707
if (flock(fd, LOCK_EX)) {
708
printf("%s: cannot lock %s\n", name, buf);
713
if ((len = read(fd, buf, sizeof(buf))) > 0) {
714
for (cp = buf; len--; ) {
715
if (*cp < '0' || *cp > '9')
717
n = n * 10 + (*cp++ - '0');
720
len = strlen(SD) + strlen(host) + 8;
721
tfname = lmktemp("tf", n, len);
722
cfname = lmktemp("cf", n, len);
723
dfname = lmktemp("df", n, len);
724
inchar = strlen(SD) + 3;
726
(void) lseek(fd, (off_t)0, 0);
727
snprintf(buf, sizeof(buf), "%03d\n", n);
728
(void) write(fd, buf, strlen(buf));
729
(void) close(fd); /* unlocks as well */
733
* Make a temp file name.
736
lmktemp(id, num, len)
742
if ((s = malloc(len)) == NULL)
743
fatal2("out of memory");
744
(void) snprintf(s, len, "%s/%sA%03d%s", SD, id, num, host);
756
fatal2(const char *msg, ...)
758
fatal2(msg, va_alist)
769
printf("%s: ", name);