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