|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)lpr.c 5.2 (Berkeley) 11/17/85";
15: #endif not lint
16:
17: /*
18: * lpr -- off line print
19: *
20: * Allows multiple printers and printers on remote machines by
21: * using information from a printer data base.
22: */
23:
24: #include <stdio.h>
25: #include <sys/types.h>
26: #include <sys/file.h>
27: #include <sys/stat.h>
28: #include <pwd.h>
29: #include <grp.h>
30: #include <signal.h>
31: #include <ctype.h>
32: #include <syslog.h>
33: #include "lp.local.h"
34:
35: char *tfname; /* tmp copy of cf before linking */
36: char *cfname; /* daemon control files, linked from tf's */
37: char *dfname; /* data files */
38:
39: int nact; /* number of jobs to act on */
40: int tfd; /* control file descriptor */
41: int mailflg; /* send mail */
42: int qflag; /* q job, but don't exec daemon */
43: char format = 'f'; /* format char for printing files */
44: int rflag; /* remove files upon completion */
45: int sflag; /* symbolic link flag */
46: int inchar; /* location to increment char in file names */
47: int ncopies = 1; /* # of copies to make */
48: int iflag; /* indentation wanted */
49: int indent; /* amount to indent */
50: int hdr = 1; /* print header or not (default is yes) */
51: int userid; /* user id */
52: char *person; /* user name */
53: char *title; /* pr'ing title */
54: char *fonts[4]; /* troff font names */
55: char *width; /* width for versatec printing */
56: char host[32]; /* host name */
57: char *class = host; /* class title on header page */
58: char *jobname; /* job name on header page */
59: char *name; /* program name */
60: char *printer; /* printer name */
61: struct stat statb;
62:
63: int MX; /* maximum number of blocks to copy */
64: int MC; /* maximum number of copies allowed */
65: int DU; /* daemon user-id */
66: char *SD; /* spool directory */
67: char *LO; /* lock file name */
68: char *RG; /* restrict group */
69: short SC; /* suppress multiple copies */
70:
71: char *getenv();
72: char *rindex();
73: char *linked();
74: int cleanup();
75:
76: /*ARGSUSED*/
77: main(argc, argv)
78: int argc;
79: char *argv[];
80: {
81: extern struct passwd *getpwuid();
82: struct passwd *pw;
83: struct group *gptr;
84: extern char *itoa();
85: register char *arg, *cp;
86: char buf[BUFSIZ];
87: int i, f;
88: struct stat stb;
89:
90: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
91: signal(SIGHUP, cleanup);
92: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
93: signal(SIGINT, cleanup);
94: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
95: signal(SIGQUIT, cleanup);
96: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
97: signal(SIGTERM, cleanup);
98:
99: name = argv[0];
100: gethostname(host, sizeof (host));
101: openlog("lpd", 0, LOG_LPR);
102:
103: while (argc > 1 && argv[1][0] == '-') {
104: argc--;
105: arg = *++argv;
106: switch (arg[1]) {
107:
108: case 'P': /* specifiy printer name */
109: if (arg[2])
110: printer = &arg[2];
111: else if (argc > 1) {
112: argc--;
113: printer = *++argv;
114: }
115: break;
116:
117: case 'C': /* classification spec */
118: hdr++;
119: if (arg[2])
120: class = &arg[2];
121: else if (argc > 1) {
122: argc--;
123: class = *++argv;
124: }
125: break;
126:
127: case 'J': /* job name */
128: hdr++;
129: if (arg[2])
130: jobname = &arg[2];
131: else if (argc > 1) {
132: argc--;
133: jobname = *++argv;
134: }
135: break;
136:
137: case 'T': /* pr's title line */
138: if (arg[2])
139: title = &arg[2];
140: else if (argc > 1) {
141: argc--;
142: title = *++argv;
143: }
144: break;
145:
146: case 'l': /* literal output */
147: case 'p': /* print using ``pr'' */
148: case 't': /* print troff output (cat files) */
149: case 'n': /* print ditroff output */
150: case 'd': /* print tex output (dvi files) */
151: case 'g': /* print graph(1G) output */
152: case 'c': /* print cifplot output */
153: case 'v': /* print vplot output */
154: format = arg[1];
155: break;
156:
157: case 'f': /* print fortran output */
158: format = 'r';
159: break;
160:
161: case '4': /* troff fonts */
162: case '3':
163: case '2':
164: case '1':
165: if (argc > 1) {
166: argc--;
167: fonts[arg[1] - '1'] = *++argv;
168: }
169: break;
170:
171: case 'w': /* versatec page width */
172: width = arg+2;
173: break;
174:
175: case 'r': /* remove file when done */
176: rflag++;
177: break;
178:
179: case 'm': /* send mail when done */
180: mailflg++;
181: break;
182:
183: case 'h': /* toggle want of header page */
184: hdr = !hdr;
185: break;
186:
187: case 's': /* try to link files */
188: sflag++;
189: break;
190:
191: case 'q': /* just q job */
192: qflag++;
193: break;
194:
195: case 'i': /* indent output */
196: iflag++;
197: indent = arg[2] ? atoi(&arg[2]) : 8;
198: break;
199:
200: case '#': /* n copies */
201: if (isdigit(arg[2])) {
202: i = atoi(&arg[2]);
203: if (i > 0)
204: ncopies = i;
205: }
206: }
207: }
208: if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
209: printer = DEFLP;
210: chkprinter(printer);
211: if (SC && ncopies > 1)
212: fatal("multiple copies are not allowed");
213: if (MC > 0 && ncopies > MC)
214: fatal("only %d copies are allowed", MC);
215: /*
216: * Get the identity of the person doing the lpr using the same
217: * algorithm as lprm.
218: */
219: userid = getuid();
220: if ((pw = getpwuid(userid)) == NULL)
221: fatal("Who are you?");
222: person = pw->pw_name;
223: /*
224: * Check for restricted group access.
225: */
226: if (RG != NULL) {
227: if ((gptr = getgrnam(RG)) == NULL)
228: fatal("Restricted group specified incorrectly");
229: if (gptr->gr_gid != getgid()) {
230: while (*gptr->gr_mem != NULL) {
231: if ((strcmp(person, *gptr->gr_mem)) == 0)
232: break;
233: gptr->gr_mem++;
234: }
235: if (*gptr->gr_mem == NULL)
236: fatal("Not a member of the restricted group");
237: }
238: }
239: /*
240: * Check to make sure queuing is enabled if userid is not root.
241: */
242: (void) sprintf(buf, "%s/%s", SD, LO);
243: if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
244: fatal("Printer queue is disabled");
245: /*
246: * Initialize the control file.
247: */
248: mktemps();
249: tfd = nfile(tfname);
250: (void) fchown(tfd, DU, -1); /* owned by daemon for protection */
251: card('H', host);
252: card('P', person);
253: if (hdr) {
254: if (jobname == NULL) {
255: if (argc == 1)
256: jobname = "stdin";
257: else
258: jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1];
259: }
260: card('J', jobname);
261: card('C', class);
262: card('L', person);
263: }
264: if (iflag)
265: card('I', itoa(indent));
266: if (mailflg)
267: card('M', person);
268: if (format == 't' || format == 'n' || format == 'd')
269: for (i = 0; i < 4; i++)
270: if (fonts[i] != NULL)
271: card('1'+i, fonts[i]);
272: if (width != NULL)
273: card('W', width);
274:
275: /*
276: * Read the files and spool them.
277: */
278: if (argc == 1)
279: copy(0, " ");
280: else while (--argc) {
281: if ((f = test(arg = *++argv)) < 0)
282: continue; /* file unreasonable */
283:
284: if (sflag && (cp = linked(arg)) != NULL) {
285: (void) sprintf(buf, "%d %d", statb.st_dev, statb.st_ino);
286: card('S', buf);
287: if (format == 'p')
288: card('T', title ? title : arg);
289: for (i = 0; i < ncopies; i++)
290: card(format, &dfname[inchar-2]);
291: card('U', &dfname[inchar-2]);
292: if (f)
293: card('U', cp);
294: card('N', arg);
295: dfname[inchar]++;
296: nact++;
297: continue;
298: }
299: if (sflag)
300: printf("%s: %s: not linked, copying instead\n", name, arg);
301: if ((i = open(arg, O_RDONLY)) < 0) {
302: printf("%s: cannot open %s\n", name, arg);
303: continue;
304: }
305: copy(i, arg);
306: (void) close(i);
307: if (f && unlink(arg) < 0)
308: printf("%s: %s: not removed\n", name, arg);
309: }
310:
311: if (nact) {
312: (void) close(tfd);
313: tfname[inchar]--;
314: /*
315: * Touch the control file to fix position in the queue.
316: */
317: if ((tfd = open(tfname, O_RDWR)) >= 0) {
318: char c;
319:
320: if (read(tfd, &c, 1) == 1 && lseek(tfd, 0L, 0) == 0 &&
321: write(tfd, &c, 1) != 1) {
322: printf("%s: cannot touch %s\n", name, tfname);
323: tfname[inchar]++;
324: cleanup();
325: }
326: (void) close(tfd);
327: }
328: if (link(tfname, cfname) < 0) {
329: printf("%s: cannot rename %s\n", name, cfname);
330: tfname[inchar]++;
331: cleanup();
332: }
333: unlink(tfname);
334: if (qflag) /* just q things up */
335: exit(0);
336: if (!startdaemon(printer))
337: printf("jobs queued, but cannot start daemon.\n");
338: exit(0);
339: }
340: cleanup();
341: /* NOTREACHED */
342: }
343:
344: /*
345: * Create the file n and copy from file descriptor f.
346: */
347: copy(f, n)
348: int f;
349: char n[];
350: {
351: register int fd, i, nr, nc;
352: char buf[BUFSIZ];
353:
354: if (format == 'p')
355: card('T', title ? title : n);
356: for (i = 0; i < ncopies; i++)
357: card(format, &dfname[inchar-2]);
358: card('U', &dfname[inchar-2]);
359: card('N', n);
360: fd = nfile(dfname);
361: nr = nc = 0;
362: while ((i = read(f, buf, BUFSIZ)) > 0) {
363: if (write(fd, buf, i) != i) {
364: printf("%s: %s: temp file write error\n", name, n);
365: break;
366: }
367: nc += i;
368: if (nc >= BUFSIZ) {
369: nc -= BUFSIZ;
370: nr++;
371: if (MX > 0 && nr > MX) {
372: printf("%s: %s: copy file is too large\n", name, n);
373: break;
374: }
375: }
376: }
377: (void) close(fd);
378: if (nc==0 && nr==0)
379: printf("%s: %s: empty input file\n", name, f ? n : "stdin");
380: else
381: nact++;
382: }
383:
384: /*
385: * Try and link the file to dfname. Return a pointer to the full
386: * path name if successful.
387: */
388: char *
389: linked(file)
390: register char *file;
391: {
392: register char *cp;
393: static char buf[BUFSIZ];
394:
395: if (*file != '/') {
396: if (getwd(buf) == NULL)
397: return(NULL);
398: while (file[0] == '.') {
399: switch (file[1]) {
400: case '/':
401: file += 2;
402: continue;
403: case '.':
404: if (file[2] == '/') {
405: if ((cp = rindex(buf, '/')) != NULL)
406: *cp = '\0';
407: file += 3;
408: continue;
409: }
410: }
411: break;
412: }
413: strcat(buf, "/");
414: strcat(buf, file);
415: file = buf;
416: }
417: return(symlink(file, dfname) ? NULL : file);
418: }
419:
420: /*
421: * Put a line into the control file.
422: */
423: card(c, p2)
424: register char c, *p2;
425: {
426: char buf[BUFSIZ];
427: register char *p1 = buf;
428: register int len = 2;
429:
430: *p1++ = c;
431: while ((c = *p2++) != '\0') {
432: *p1++ = c;
433: len++;
434: }
435: *p1++ = '\n';
436: write(tfd, buf, len);
437: }
438:
439: /*
440: * Create a new file in the spool directory.
441: */
442: nfile(n)
443: char *n;
444: {
445: register f;
446: int oldumask = umask(0); /* should block signals */
447:
448: f = creat(n, FILMOD);
449: (void) umask(oldumask);
450: if (f < 0) {
451: printf("%s: cannot create %s\n", name, n);
452: cleanup();
453: }
454: if (fchown(f, userid, -1) < 0) {
455: printf("%s: cannot chown %s\n", name, n);
456: cleanup();
457: }
458: if (++n[inchar] > 'z') {
459: if (++n[inchar-2] == 't') {
460: printf("too many files - break up the job\n");
461: cleanup();
462: }
463: n[inchar] = 'A';
464: } else if (n[inchar] == '[')
465: n[inchar] = 'a';
466: return(f);
467: }
468:
469: /*
470: * Cleanup after interrupts and errors.
471: */
472: cleanup()
473: {
474: register i;
475:
476: signal(SIGHUP, SIG_IGN);
477: signal(SIGINT, SIG_IGN);
478: signal(SIGQUIT, SIG_IGN);
479: signal(SIGTERM, SIG_IGN);
480: i = inchar;
481: if (tfname)
482: do
483: unlink(tfname);
484: while (tfname[i]-- != 'A');
485: if (cfname)
486: do
487: unlink(cfname);
488: while (cfname[i]-- != 'A');
489: if (dfname)
490: do {
491: do
492: unlink(dfname);
493: while (dfname[i]-- != 'A');
494: dfname[i] = 'z';
495: } while (dfname[i-2]-- != 'd');
496: exit(1);
497: }
498:
499: /*
500: * Test to see if this is a printable file.
501: * Return -1 if it is not, 0 if its printable, and 1 if
502: * we should remove it after printing.
503: */
504: test(file)
505: char *file;
506: {
507: struct exec execb;
508: register int fd;
509: register char *cp;
510:
511: if (access(file, 4) < 0) {
512: printf("%s: cannot access %s\n", name, file);
513: return(-1);
514: }
515: if (stat(file, &statb) < 0) {
516: printf("%s: cannot stat %s\n", name, file);
517: return(-1);
518: }
519: if ((statb.st_mode & S_IFMT) == S_IFDIR) {
520: printf("%s: %s is a directory\n", name, file);
521: return(-1);
522: }
523: if (statb.st_size == 0) {
524: printf("%s: %s is an empty file\n", name, file);
525: return(-1);
526: }
527: if ((fd = open(file, O_RDONLY)) < 0) {
528: printf("%s: cannot open %s\n", name, file);
529: return(-1);
530: }
531: if (read(fd, &execb, sizeof(execb)) == sizeof(execb))
532: switch(execb.a_magic) {
533: case A_MAGIC1:
534: case A_MAGIC2:
535: case A_MAGIC3:
536: #ifdef A_MAGIC4
537: case A_MAGIC4:
538: #endif
539: printf("%s: %s is an executable program", name, file);
540: goto error1;
541:
542: case ARMAG:
543: printf("%s: %s is an archive file", name, file);
544: goto error1;
545: }
546: (void) close(fd);
547: if (rflag) {
548: if ((cp = rindex(file, '/')) == NULL) {
549: if (access(".", 2) == 0)
550: return(1);
551: } else {
552: *cp = '\0';
553: fd = access(file, 2);
554: *cp = '/';
555: if (fd == 0)
556: return(1);
557: }
558: printf("%s: %s: is not removable by you\n", name, file);
559: }
560: return(0);
561:
562: error1:
563: printf(" and is unprintable\n");
564: (void) close(fd);
565: return(-1);
566: }
567:
568: /*
569: * itoa - integer to string conversion
570: */
571: char *
572: itoa(i)
573: register int i;
574: {
575: static char b[10] = "########";
576: register char *p;
577:
578: p = &b[8];
579: do
580: *p-- = i%10 + '0';
581: while (i /= 10);
582: return(++p);
583: }
584:
585: /*
586: * Perform lookup for printer name or abbreviation --
587: */
588: chkprinter(s)
589: char *s;
590: {
591: int status;
592: char buf[BUFSIZ];
593: static char pbuf[BUFSIZ/2];
594: char *bp = pbuf;
595: extern char *pgetstr();
596:
597: if ((status = pgetent(buf, s)) < 0)
598: fatal("cannot open printer description file");
599: else if (status == 0)
600: fatal("%s: unknown printer", s);
601: if ((SD = pgetstr("sd", &bp)) == NULL)
602: SD = DEFSPOOL;
603: if ((LO = pgetstr("lo", &bp)) == NULL)
604: LO = DEFLOCK;
605: RG = pgetstr("rg", &bp);
606: if ((MX = pgetnum("mx")) < 0)
607: MX = DEFMX;
608: if ((MC = pgetnum("mc")) < 0)
609: MC = DEFMAXCOPIES;
610: if ((DU = pgetnum("du")) < 0)
611: DU = DEFUID;
612: SC = pgetflag("sc");
613: }
614:
615: /*
616: * Make the temp files.
617: */
618: mktemps()
619: {
620: register int c, len, fd, n;
621: register char *cp;
622: char buf[BUFSIZ];
623: char *mktemp();
624:
625: (void) sprintf(buf, "%s/.seq", SD);
626: if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
627: printf("%s: cannot create %s\n", name, buf);
628: exit(1);
629: }
630: if (flock(fd, LOCK_EX)) {
631: printf("%s: cannot lock %s\n", name, buf);
632: exit(1);
633: }
634: n = 0;
635: if ((len = read(fd, buf, sizeof(buf))) > 0) {
636: for (cp = buf; len--; ) {
637: if (*cp < '0' || *cp > '9')
638: break;
639: n = n * 10 + (*cp++ - '0');
640: }
641: }
642: len = strlen(SD) + strlen(host) + 8;
643: tfname = mktemp("tf", n, len);
644: cfname = mktemp("cf", n, len);
645: dfname = mktemp("df", n, len);
646: inchar = strlen(SD) + 3;
647: n = (n + 1) % 1000;
648: (void) lseek(fd, 0L, 0);
649: sprintf(buf, "%03d\n", n);
650: (void) write(fd, buf, strlen(buf));
651: (void) close(fd); /* unlocks as well */
652: }
653:
654: /*
655: * Make a temp file name.
656: */
657: char *
658: mktemp(id, num, len)
659: char *id;
660: int num, len;
661: {
662: register char *s;
663: extern char *malloc();
664:
665: if ((s = malloc(len)) == NULL)
666: fatal("out of memory");
667: (void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host);
668: return(s);
669: }
670:
671: /*VARARGS1*/
672: fatal(msg, a1, a2, a3)
673: char *msg;
674: {
675: printf("%s: ", name);
676: printf(msg, a1, a2, a3);
677: putchar('\n');
678: exit(1);
679: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.