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