|
|
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: static char sccsid[] = "@(#)printjob.c 5.2 (Berkeley) 9/17/85";
9: #endif not lint
10:
11: /*
12: * printjob -- print jobs in the queue.
13: *
14: * NOTE: the lock file is used to pass information to lpq and lprm.
15: * it does not need to be removed because file locks are dynamic.
16: */
17:
18: #include "lp.h"
19:
20: #define DORETURN 0 /* absorb fork error */
21: #define DOABORT 1 /* abort if dofork fails */
22:
23: /*
24: * Error tokens
25: */
26: #define REPRINT -2
27: #define ERROR -1
28: #define OK 0
29: #define FATALERR 1
30: #define NOACCT 2
31: #define FILTERERR 3
32: #define ACCESS 4
33:
34: char title[80]; /* ``pr'' title */
35: FILE *cfp; /* control file */
36: int pfd; /* printer file descriptor */
37: int ofd; /* output filter file descriptor */
38: int lfd; /* lock file descriptor */
39: int pid; /* pid of lpd process */
40: int prchild; /* id of pr process */
41: int child; /* id of any filters */
42: int ofilter; /* id of output filter, if any */
43: int tof; /* true if at top of form */
44: int remote; /* true if sending files to remote */
45: dev_t fdev; /* device of file pointed to by symlink */
46: ino_t fino; /* inode of file pointed to by symlink */
47:
48: char fromhost[32]; /* user's host machine */
49: char logname[32]; /* user's login name */
50: char jobname[100]; /* job or file name */
51: char class[32]; /* classification field */
52: char width[10] = "-w"; /* page width in characters */
53: char length[10] = "-l"; /* page length in lines */
54: char pxwidth[10] = "-x"; /* page width in pixels */
55: char pxlength[10] = "-y"; /* page length in pixels */
56: char indent[10] = "-i0"; /* indentation size in characters */
57: char tmpfile[] = "errsXXXXXX"; /* file name for filter output */
58:
59: printjob()
60: {
61: struct stat stb;
62: register struct queue *q, **qp;
63: struct queue **queue;
64: register int i, nitems;
65: long pidoff;
66: int count = 0;
67: extern int abortpr();
68:
69: init(); /* set up capabilities */
70: (void) write(1, "", 1); /* ack that daemon is started */
71: (void) close(2); /* set up log file */
72: if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
73: syslog(LOG_ERR, "%s: %m", LF);
74: (void) open("/dev/null", O_WRONLY);
75: }
76: setgid(getegid());
77: pid = getpid(); /* for use with lprm */
78: setpgrp(0, pid);
79: signal(SIGHUP, abortpr);
80: signal(SIGINT, abortpr);
81: signal(SIGQUIT, abortpr);
82: signal(SIGTERM, abortpr);
83:
84: (void) mktemp(tmpfile);
85:
86: /*
87: * uses short form file names
88: */
89: if (chdir(SD) < 0) {
90: syslog(LOG_ERR, "%s: %m", SD);
91: exit(1);
92: }
93: if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
94: exit(0); /* printing disabled */
95: lfd = open(LO, O_WRONLY|O_CREAT, 0644);
96: if (lfd < 0) {
97: syslog(LOG_ERR, "%s: %s: %m", printer, LO);
98: exit(1);
99: }
100: if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
101: if (errno == EWOULDBLOCK) /* active deamon present */
102: exit(0);
103: syslog(LOG_ERR, "%s: %s: %m", printer, LO);
104: exit(1);
105: }
106: ftruncate(lfd, 0);
107: /*
108: * write process id for others to know
109: */
110: sprintf(line, "%u\n", pid);
111: pidoff = i = strlen(line);
112: if (write(lfd, line, i) != i) {
113: syslog(LOG_ERR, "%s: %s: %m", printer, LO);
114: exit(1);
115: }
116: /*
117: * search the spool directory for work and sort by queue order.
118: */
119: if ((nitems = getq(&queue)) < 0) {
120: syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
121: exit(1);
122: }
123: if (nitems == 0) /* no work to do */
124: exit(0);
125: if (stb.st_mode & 01) { /* reset queue flag */
126: if (fchmod(lfd, stb.st_mode & 0776) < 0)
127: syslog(LOG_ERR, "%s: %s: %m", printer, LO);
128: }
129: openpr(); /* open printer or remote */
130: again:
131: /*
132: * we found something to do now do it --
133: * write the name of the current control file into the lock file
134: * so the spool queue program can tell what we're working on
135: */
136: for (qp = queue; nitems--; free((char *) q)) {
137: q = *qp++;
138: if (stat(q->q_name, &stb) < 0)
139: continue;
140: restart:
141: (void) lseek(lfd, pidoff, 0);
142: (void) sprintf(line, "%s\n", q->q_name);
143: i = strlen(line);
144: if (write(lfd, line, i) != i)
145: syslog(LOG_ERR, "%s: %s: %m", printer, LO);
146: if (!remote)
147: i = printit(q->q_name);
148: else
149: i = sendit(q->q_name);
150: /*
151: * Check to see if we are supposed to stop printing or
152: * if we are to rebuild the queue.
153: */
154: if (fstat(lfd, &stb) == 0) {
155: /* stop printing before starting next job? */
156: if (stb.st_mode & 0100)
157: goto done;
158: /* rebuild queue (after lpc topq) */
159: if (stb.st_mode & 01) {
160: for (free((char *) q); nitems--; free((char *) q))
161: q = *qp++;
162: if (fchmod(lfd, stb.st_mode & 0776) < 0)
163: syslog(LOG_WARNING, "%s: %s: %m",
164: printer, LO);
165: break;
166: }
167: }
168: if (i == OK) /* file ok and printed */
169: count++;
170: else if (i == REPRINT) { /* try reprinting the job */
171: syslog(LOG_INFO, "restarting %s", printer);
172: if (ofilter > 0) {
173: kill(ofilter, SIGCONT); /* to be sure */
174: (void) close(ofd);
175: while ((i = wait(0)) > 0 && i != ofilter)
176: ;
177: ofilter = 0;
178: }
179: (void) close(pfd); /* close printer */
180: if (ftruncate(lfd, pidoff) < 0)
181: syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
182: openpr(); /* try to reopen printer */
183: goto restart;
184: }
185: }
186: free((char *) queue);
187: /*
188: * search the spool directory for more work.
189: */
190: if ((nitems = getq(&queue)) < 0) {
191: syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
192: exit(1);
193: }
194: if (nitems == 0) { /* no more work to do */
195: done:
196: if (count > 0) { /* Files actually printed */
197: if (!SF && !tof)
198: (void) write(ofd, FF, strlen(FF));
199: if (TR != NULL) /* output trailer */
200: (void) write(ofd, TR, strlen(TR));
201: }
202: (void) unlink(tmpfile);
203: exit(0);
204: }
205: goto again;
206: }
207:
208: char fonts[4][50]; /* fonts for troff */
209:
210: char ifonts[4][18] = {
211: "/usr/lib/vfont/R",
212: "/usr/lib/vfont/I",
213: "/usr/lib/vfont/B",
214: "/usr/lib/vfont/S"
215: };
216:
217: /*
218: * The remaining part is the reading of the control file (cf)
219: * and performing the various actions.
220: */
221: printit(file)
222: char *file;
223: {
224: register int i;
225: char *cp;
226: int bombed = OK;
227:
228: /*
229: * open control file; ignore if no longer there.
230: */
231: if ((cfp = fopen(file, "r")) == NULL) {
232: syslog(LOG_INFO, "%s: %s: %m", printer, file);
233: return(OK);
234: }
235: /*
236: * Reset troff fonts.
237: */
238: for (i = 0; i < 4; i++)
239: strcpy(fonts[i], ifonts[i]);
240: strcpy(width+2, "0");
241: strcpy(indent+2, "0");
242:
243: /*
244: * read the control file for work to do
245: *
246: * file format -- first character in the line is a command
247: * rest of the line is the argument.
248: * valid commands are:
249: *
250: * S -- "stat info" for symbolic link protection
251: * J -- "job name" on banner page
252: * C -- "class name" on banner page
253: * L -- "literal" user's name to print on banner
254: * T -- "title" for pr
255: * H -- "host name" of machine where lpr was done
256: * P -- "person" user's login name
257: * I -- "indent" amount to indent output
258: * f -- "file name" name of text file to print
259: * l -- "file name" text file with control chars
260: * p -- "file name" text file to print with pr(1)
261: * t -- "file name" troff(1) file to print
262: * n -- "file name" ditroff(1) file to print
263: * d -- "file name" dvi file to print
264: * g -- "file name" plot(1G) file to print
265: * v -- "file name" plain raster file to print
266: * c -- "file name" cifplot file to print
267: * 1 -- "R font file" for troff
268: * 2 -- "I font file" for troff
269: * 3 -- "B font file" for troff
270: * 4 -- "S font file" for troff
271: * N -- "name" of file (used by lpq)
272: * U -- "unlink" name of file to remove
273: * (after we print it. (Pass 2 only)).
274: * M -- "mail" to user when done printing
275: *
276: * getline reads a line and expands tabs to blanks
277: */
278:
279: /* pass 1 */
280:
281: while (getline(cfp))
282: switch (line[0]) {
283: case 'H':
284: strcpy(fromhost, line+1);
285: if (class[0] == '\0')
286: strncpy(class, line+1, sizeof(class)-1);
287: continue;
288:
289: case 'P':
290: strncpy(logname, line+1, sizeof(logname)-1);
291: if (RS) { /* restricted */
292: if (getpwnam(logname) == (struct passwd *)0) {
293: bombed = NOACCT;
294: sendmail(line+1, bombed);
295: goto pass2;
296: }
297: }
298: continue;
299:
300: case 'S':
301: cp = line+1;
302: i = 0;
303: while (*cp >= '0' && *cp <= '9')
304: i = i * 10 + (*cp++ - '0');
305: fdev = i;
306: cp++;
307: i = 0;
308: while (*cp >= '0' && *cp <= '9')
309: i = i * 10 + (*cp++ - '0');
310: fino = i;
311: continue;
312:
313: case 'J':
314: if (line[1] != '\0')
315: strncpy(jobname, line+1, sizeof(jobname)-1);
316: else
317: strcpy(jobname, " ");
318: continue;
319:
320: case 'C':
321: if (line[1] != '\0')
322: strncpy(class, line+1, sizeof(class)-1);
323: else if (class[0] == '\0')
324: gethostname(class, sizeof(class));
325: continue;
326:
327: case 'T': /* header title for pr */
328: strncpy(title, line+1, sizeof(title)-1);
329: continue;
330:
331: case 'L': /* identification line */
332: if (!SH && !HL)
333: banner(line+1, jobname);
334: continue;
335:
336: case '1': /* troff fonts */
337: case '2':
338: case '3':
339: case '4':
340: if (line[1] != '\0')
341: strcpy(fonts[line[0]-'1'], line+1);
342: continue;
343:
344: case 'W': /* page width */
345: strncpy(width+2, line+1, sizeof(width)-3);
346: continue;
347:
348: case 'I': /* indent amount */
349: strncpy(indent+2, line+1, sizeof(indent)-3);
350: continue;
351:
352: default: /* some file to print */
353: switch (i = print(line[0], line+1)) {
354: case ERROR:
355: if (bombed == OK)
356: bombed = FATALERR;
357: break;
358: case REPRINT:
359: (void) fclose(cfp);
360: return(REPRINT);
361: case FILTERERR:
362: case ACCESS:
363: bombed = i;
364: sendmail(logname, bombed);
365: }
366: title[0] = '\0';
367: continue;
368:
369: case 'N':
370: case 'U':
371: case 'M':
372: continue;
373: }
374:
375: /* pass 2 */
376:
377: pass2:
378: fseek(cfp, 0L, 0);
379: while (getline(cfp))
380: switch (line[0]) {
381: case 'L': /* identification line */
382: if (!SH && HL)
383: banner(line+1, jobname);
384: continue;
385:
386: case 'M':
387: if (bombed < NOACCT) /* already sent if >= NOACCT */
388: sendmail(line+1, bombed);
389: continue;
390:
391: case 'U':
392: (void) unlink(line+1);
393: }
394: /*
395: * clean-up in case another control file exists
396: */
397: (void) fclose(cfp);
398: (void) unlink(file);
399: return(bombed == OK ? OK : ERROR);
400: }
401:
402: /*
403: * Print a file.
404: * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
405: * Return -1 if a non-recoverable error occured,
406: * 2 if the filter detected some errors (but printed the job anyway),
407: * 1 if we should try to reprint this job and
408: * 0 if all is well.
409: * Note: all filters take stdin as the file, stdout as the printer,
410: * stderr as the log file, and must not ignore SIGINT.
411: */
412: print(format, file)
413: int format;
414: char *file;
415: {
416: register int n;
417: register char *prog;
418: int fi, fo;
419: char *av[15], buf[BUFSIZ];
420: int pid, p[2], stopped = 0;
421: union wait status;
422: struct stat stb;
423:
424: if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
425: return(ERROR);
426: /*
427: * Check to see if data file is a symbolic link. If so, it should
428: * still point to the same file or someone is trying to print
429: * something he shouldn't.
430: */
431: if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
432: (stb.st_dev != fdev || stb.st_ino != fino))
433: return(ACCESS);
434: if (!SF && !tof) { /* start on a fresh page */
435: (void) write(ofd, FF, strlen(FF));
436: tof = 1;
437: }
438: if (IF == NULL && (format == 'f' || format == 'l')) {
439: tof = 0;
440: while ((n = read(fi, buf, BUFSIZ)) > 0)
441: if (write(ofd, buf, n) != n) {
442: (void) close(fi);
443: return(REPRINT);
444: }
445: (void) close(fi);
446: return(OK);
447: }
448: switch (format) {
449: case 'p': /* print file using 'pr' */
450: if (IF == NULL) { /* use output filter */
451: prog = PR;
452: av[0] = "pr";
453: av[1] = width;
454: av[2] = length;
455: av[3] = "-h";
456: av[4] = *title ? title : " ";
457: av[5] = 0;
458: fo = ofd;
459: goto start;
460: }
461: pipe(p);
462: if ((prchild = dofork(DORETURN)) == 0) { /* child */
463: dup2(fi, 0); /* file is stdin */
464: dup2(p[1], 1); /* pipe is stdout */
465: for (n = 3; n < NOFILE; n++)
466: (void) close(n);
467: execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
468: syslog(LOG_ERR, "cannot execl %s", PR);
469: exit(2);
470: }
471: (void) close(p[1]); /* close output side */
472: (void) close(fi);
473: if (prchild < 0) {
474: prchild = 0;
475: (void) close(p[0]);
476: return(ERROR);
477: }
478: fi = p[0]; /* use pipe for input */
479: case 'f': /* print plain text file */
480: prog = IF;
481: av[1] = width;
482: av[2] = length;
483: av[3] = indent;
484: n = 4;
485: break;
486: case 'l': /* like 'f' but pass control characters */
487: prog = IF;
488: av[1] = "-c";
489: av[2] = width;
490: av[3] = length;
491: av[4] = indent;
492: n = 5;
493: break;
494: case 'r': /* print a fortran text file */
495: prog = RF;
496: av[1] = width;
497: av[2] = length;
498: n = 3;
499: break;
500: case 't': /* print troff output */
501: case 'n': /* print ditroff output */
502: case 'd': /* print tex output */
503: (void) unlink(".railmag");
504: if ((fo = creat(".railmag", FILMOD)) < 0) {
505: syslog(LOG_ERR, "%s: cannot create .railmag", printer);
506: (void) unlink(".railmag");
507: } else {
508: for (n = 0; n < 4; n++) {
509: if (fonts[n][0] != '/')
510: (void) write(fo, "/usr/lib/vfont/", 15);
511: (void) write(fo, fonts[n], strlen(fonts[n]));
512: (void) write(fo, "\n", 1);
513: }
514: (void) close(fo);
515: }
516: prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
517: av[1] = pxwidth;
518: av[2] = pxlength;
519: n = 3;
520: break;
521: case 'c': /* print cifplot output */
522: prog = CF;
523: av[1] = pxwidth;
524: av[2] = pxlength;
525: n = 3;
526: break;
527: case 'g': /* print plot(1G) output */
528: prog = GF;
529: av[1] = pxwidth;
530: av[2] = pxlength;
531: n = 3;
532: break;
533: case 'v': /* print raster output */
534: prog = VF;
535: av[1] = pxwidth;
536: av[2] = pxlength;
537: n = 3;
538: break;
539: default:
540: (void) close(fi);
541: syslog(LOG_ERR, "%s: illegal format character '%c'",
542: printer, format);
543: return(ERROR);
544: }
545: if ((av[0] = rindex(prog, '/')) != NULL)
546: av[0]++;
547: else
548: av[0] = prog;
549: av[n++] = "-n";
550: av[n++] = logname;
551: av[n++] = "-h";
552: av[n++] = fromhost;
553: av[n++] = AF;
554: av[n] = 0;
555: fo = pfd;
556: if (ofilter > 0) { /* stop output filter */
557: write(ofd, "\031\1", 2);
558: while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
559: ;
560: if (status.w_stopval != WSTOPPED) {
561: (void) close(fi);
562: syslog(LOG_WARNING, "%s: output filter died (%d)",
563: printer, status.w_retcode);
564: return(REPRINT);
565: }
566: stopped++;
567: }
568: start:
569: if ((child = dofork(DORETURN)) == 0) { /* child */
570: dup2(fi, 0);
571: dup2(fo, 1);
572: n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
573: if (n >= 0)
574: dup2(n, 2);
575: for (n = 3; n < NOFILE; n++)
576: (void) close(n);
577: execv(prog, av);
578: syslog(LOG_ERR, "cannot execv %s", prog);
579: exit(2);
580: }
581: (void) close(fi);
582: if (child < 0)
583: status.w_retcode = 100;
584: else
585: while ((pid = wait(&status)) > 0 && pid != child)
586: ;
587: child = 0;
588: prchild = 0;
589: if (stopped) { /* restart output filter */
590: if (kill(ofilter, SIGCONT) < 0) {
591: syslog(LOG_ERR, "cannot restart output filter");
592: exit(1);
593: }
594: }
595: tof = 0;
596: if (!WIFEXITED(status)) {
597: syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
598: printer, format, status.w_termsig);
599: return(ERROR);
600: }
601: switch (status.w_retcode) {
602: case 0:
603: tof = 1;
604: return(OK);
605: case 1:
606: return(REPRINT);
607: default:
608: syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
609: printer, format, status.w_retcode);
610: case 2:
611: return(ERROR);
612: }
613: }
614:
615: /*
616: * Send the daemon control file (cf) and any data files.
617: * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
618: * 0 if all is well.
619: */
620: sendit(file)
621: char *file;
622: {
623: register int i, err = OK;
624: char *cp, last[BUFSIZ];
625:
626: /*
627: * open control file
628: */
629: if ((cfp = fopen(file, "r")) == NULL)
630: return(OK);
631: /*
632: * read the control file for work to do
633: *
634: * file format -- first character in the line is a command
635: * rest of the line is the argument.
636: * commands of interest are:
637: *
638: * a-z -- "file name" name of file to print
639: * U -- "unlink" name of file to remove
640: * (after we print it. (Pass 2 only)).
641: */
642:
643: /*
644: * pass 1
645: */
646: while (getline(cfp)) {
647: again:
648: if (line[0] == 'S') {
649: cp = line+1;
650: i = 0;
651: while (*cp >= '0' && *cp <= '9')
652: i = i * 10 + (*cp++ - '0');
653: fdev = i;
654: cp++;
655: i = 0;
656: while (*cp >= '0' && *cp <= '9')
657: i = i * 10 + (*cp++ - '0');
658: fino = i;
659: continue;
660: }
661: if (line[0] >= 'a' && line[0] <= 'z') {
662: strcpy(last, line);
663: while (i = getline(cfp))
664: if (strcmp(last, line))
665: break;
666: switch (sendfile('\3', last+1)) {
667: case OK:
668: if (i)
669: goto again;
670: break;
671: case REPRINT:
672: (void) fclose(cfp);
673: return(REPRINT);
674: case ACCESS:
675: sendmail(logname, ACCESS);
676: case ERROR:
677: err = ERROR;
678: }
679: break;
680: }
681: }
682: if (err == OK && sendfile('\2', file) > 0) {
683: (void) fclose(cfp);
684: return(REPRINT);
685: }
686: /*
687: * pass 2
688: */
689: fseek(cfp, 0L, 0);
690: while (getline(cfp))
691: if (line[0] == 'U')
692: (void) unlink(line+1);
693: /*
694: * clean-up in case another control file exists
695: */
696: (void) fclose(cfp);
697: (void) unlink(file);
698: return(err);
699: }
700:
701: /*
702: * Send a data file to the remote machine and spool it.
703: * Return positive if we should try resending.
704: */
705: sendfile(type, file)
706: char type, *file;
707: {
708: register int f, i, amt;
709: struct stat stb;
710: char buf[BUFSIZ];
711: int sizerr, resp;
712:
713: if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
714: return(ERROR);
715: /*
716: * Check to see if data file is a symbolic link. If so, it should
717: * still point to the same file or someone is trying to print something
718: * he shouldn't.
719: */
720: if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
721: (stb.st_dev != fdev || stb.st_ino != fino))
722: return(ACCESS);
723: (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
724: amt = strlen(buf);
725: for (i = 0; ; i++) {
726: if (write(pfd, buf, amt) != amt ||
727: (resp = response()) < 0 || resp == '\1') {
728: (void) close(f);
729: return(REPRINT);
730: } else if (resp == '\0')
731: break;
732: if (i == 0)
733: status("no space on remote; waiting for queue to drain");
734: if (i == 10)
735: syslog(LOG_ALERT, "%s: can't send to %s; queue full",
736: printer, RM);
737: sleep(5 * 60);
738: }
739: if (i)
740: status("sending to %s", RM);
741: sizerr = 0;
742: for (i = 0; i < stb.st_size; i += BUFSIZ) {
743: amt = BUFSIZ;
744: if (i + amt > stb.st_size)
745: amt = stb.st_size - i;
746: if (sizerr == 0 && read(f, buf, amt) != amt)
747: sizerr = 1;
748: if (write(pfd, buf, amt) != amt) {
749: (void) close(f);
750: return(REPRINT);
751: }
752: }
753: (void) close(f);
754: if (sizerr) {
755: syslog(LOG_INFO, "%s: %s: changed size", printer, file);
756: /* tell recvjob to ignore this file */
757: (void) write(pfd, "\1", 1);
758: return(ERROR);
759: }
760: if (write(pfd, "", 1) != 1 || response())
761: return(REPRINT);
762: return(OK);
763: }
764:
765: /*
766: * Check to make sure there have been no errors and that both programs
767: * are in sync with eachother.
768: * Return non-zero if the connection was lost.
769: */
770: response()
771: {
772: char resp;
773:
774: if (read(pfd, &resp, 1) != 1) {
775: syslog(LOG_INFO, "%s: lost connection", printer);
776: return(-1);
777: }
778: return(resp);
779: }
780:
781: /*
782: * Banner printing stuff
783: */
784: banner(name1, name2)
785: char *name1, *name2;
786: {
787: time_t tvec;
788: extern char *ctime();
789:
790: time(&tvec);
791: if (!SF && !tof)
792: (void) write(ofd, FF, strlen(FF));
793: if (SB) { /* short banner only */
794: if (class[0]) {
795: (void) write(ofd, class, strlen(class));
796: (void) write(ofd, ":", 1);
797: }
798: (void) write(ofd, name1, strlen(name1));
799: (void) write(ofd, " Job: ", 7);
800: (void) write(ofd, name2, strlen(name2));
801: (void) write(ofd, " Date: ", 8);
802: (void) write(ofd, ctime(&tvec), 24);
803: (void) write(ofd, "\n", 1);
804: } else { /* normal banner */
805: (void) write(ofd, "\n\n\n", 3);
806: scan_out(ofd, name1, '\0');
807: (void) write(ofd, "\n\n", 2);
808: scan_out(ofd, name2, '\0');
809: if (class[0]) {
810: (void) write(ofd,"\n\n\n",3);
811: scan_out(ofd, class, '\0');
812: }
813: (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
814: (void) write(ofd, name2, strlen(name2));
815: (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
816: (void) write(ofd, ctime(&tvec), 24);
817: (void) write(ofd, "\n", 1);
818: }
819: if (!SF)
820: (void) write(ofd, FF, strlen(FF));
821: tof = 1;
822: }
823:
824: char *
825: scnline(key, p, c)
826: register char key, *p;
827: char c;
828: {
829: register scnwidth;
830:
831: for (scnwidth = WIDTH; --scnwidth;) {
832: key <<= 1;
833: *p++ = key & 0200 ? c : BACKGND;
834: }
835: return (p);
836: }
837:
838: #define TRC(q) (((q)-' ')&0177)
839:
840: scan_out(scfd, scsp, dlm)
841: int scfd;
842: char *scsp, dlm;
843: {
844: register char *strp;
845: register nchrs, j;
846: char outbuf[LINELEN+1], *sp, c, cc;
847: int d, scnhgt;
848: extern char scnkey[][HEIGHT]; /* in lpdchar.c */
849:
850: for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
851: strp = &outbuf[0];
852: sp = scsp;
853: for (nchrs = 0; ; ) {
854: d = dropit(c = TRC(cc = *sp++));
855: if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
856: for (j = WIDTH; --j;)
857: *strp++ = BACKGND;
858: else
859: strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
860: if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
861: break;
862: *strp++ = BACKGND;
863: *strp++ = BACKGND;
864: }
865: while (*--strp == BACKGND && strp >= outbuf)
866: ;
867: strp++;
868: *strp++ = '\n';
869: (void) write(scfd, outbuf, strp-outbuf);
870: }
871: }
872:
873: dropit(c)
874: char c;
875: {
876: switch(c) {
877:
878: case TRC('_'):
879: case TRC(';'):
880: case TRC(','):
881: case TRC('g'):
882: case TRC('j'):
883: case TRC('p'):
884: case TRC('q'):
885: case TRC('y'):
886: return (DROP);
887:
888: default:
889: return (0);
890: }
891: }
892:
893: /*
894: * sendmail ---
895: * tell people about job completion
896: */
897: sendmail(user, bombed)
898: char *user;
899: int bombed;
900: {
901: register int i;
902: int p[2], s;
903: register char *cp;
904: char buf[100];
905: struct stat stb;
906: FILE *fp;
907:
908: pipe(p);
909: if ((s = dofork(DORETURN)) == 0) { /* child */
910: dup2(p[0], 0);
911: for (i = 3; i < NOFILE; i++)
912: (void) close(i);
913: if ((cp = rindex(MAIL, '/')) != NULL)
914: cp++;
915: else
916: cp = MAIL;
917: sprintf(buf, "%s@%s", user, fromhost);
918: execl(MAIL, cp, buf, 0);
919: exit(0);
920: } else if (s > 0) { /* parent */
921: dup2(p[1], 1);
922: printf("To: %s@%s\n", user, fromhost);
923: printf("Subject: printer job\n\n");
924: printf("Your printer job ");
925: if (*jobname)
926: printf("(%s) ", jobname);
927: switch (bombed) {
928: case OK:
929: printf("\ncompleted successfully\n");
930: break;
931: default:
932: case FATALERR:
933: printf("\ncould not be printed\n");
934: break;
935: case NOACCT:
936: printf("\ncould not be printed without an account on %s\n", host);
937: break;
938: case FILTERERR:
939: if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
940: (fp = fopen(tmpfile, "r")) == NULL) {
941: printf("\nwas printed but had some errors\n");
942: break;
943: }
944: printf("\nwas printed but had the following errors:\n");
945: while ((i = getc(fp)) != EOF)
946: putchar(i);
947: (void) fclose(fp);
948: break;
949: case ACCESS:
950: printf("\nwas not printed because it was not linked to the original file\n");
951: }
952: fflush(stdout);
953: (void) close(1);
954: }
955: (void) close(p[0]);
956: (void) close(p[1]);
957: wait(&s);
958: }
959:
960: /*
961: * dofork - fork with retries on failure
962: */
963: dofork(action)
964: int action;
965: {
966: register int i, pid;
967:
968: for (i = 0; i < 20; i++) {
969: if ((pid = fork()) < 0) {
970: sleep((unsigned)(i*i));
971: continue;
972: }
973: /*
974: * Child should run as daemon instead of root
975: */
976: if (pid == 0)
977: setuid(DU);
978: return(pid);
979: }
980: syslog(LOG_ERR, "can't fork");
981:
982: switch (action) {
983: case DORETURN:
984: return (-1);
985: default:
986: syslog(LOG_ERR, "bad action (%d) to dofork", action);
987: /*FALL THRU*/
988: case DOABORT:
989: exit(1);
990: }
991: /*NOTREACHED*/
992: }
993:
994: /*
995: * Kill child processes to abort current job.
996: */
997: abortpr()
998: {
999: (void) unlink(tmpfile);
1000: kill(0, SIGINT);
1001: if (ofilter > 0)
1002: kill(ofilter, SIGCONT);
1003: while (wait(0) > 0)
1004: ;
1005: exit(0);
1006: }
1007:
1008: init()
1009: {
1010: int status;
1011:
1012: if ((status = pgetent(line, printer)) < 0) {
1013: syslog(LOG_ERR, "can't open printer description file");
1014: exit(1);
1015: } else if (status == 0) {
1016: syslog(LOG_ERR, "unknown printer: %s", printer);
1017: exit(1);
1018: }
1019: if ((LP = pgetstr("lp", &bp)) == NULL)
1020: LP = DEFDEVLP;
1021: if ((RP = pgetstr("rp", &bp)) == NULL)
1022: RP = DEFLP;
1023: if ((LO = pgetstr("lo", &bp)) == NULL)
1024: LO = DEFLOCK;
1025: if ((ST = pgetstr("st", &bp)) == NULL)
1026: ST = DEFSTAT;
1027: if ((LF = pgetstr("lf", &bp)) == NULL)
1028: LF = DEFLOGF;
1029: if ((SD = pgetstr("sd", &bp)) == NULL)
1030: SD = DEFSPOOL;
1031: if ((DU = pgetnum("du")) < 0)
1032: DU = DEFUID;
1033: if ((FF = pgetstr("ff", &bp)) == NULL)
1034: FF = DEFFF;
1035: if ((PW = pgetnum("pw")) < 0)
1036: PW = DEFWIDTH;
1037: sprintf(&width[2], "%d", PW);
1038: if ((PL = pgetnum("pl")) < 0)
1039: PL = DEFLENGTH;
1040: sprintf(&length[2], "%d", PL);
1041: if ((PX = pgetnum("px")) < 0)
1042: PX = 0;
1043: sprintf(&pxwidth[2], "%d", PX);
1044: if ((PY = pgetnum("py")) < 0)
1045: PY = 0;
1046: sprintf(&pxlength[2], "%d", PY);
1047: RM = pgetstr("rm", &bp);
1048: /*
1049: * Figure out whether the local machine is the same as the remote
1050: * machine entry (if it exists). If not, then ignore the local
1051: * queue information.
1052: */
1053: if (RM != (char *) NULL) {
1054: char name[256];
1055: struct hostent *hp;
1056:
1057: /* get the standard network name of the local host */
1058: gethostname(name, sizeof(name));
1059: name[sizeof(name)-1] = '\0';
1060: hp = gethostbyname(name);
1061: if (hp == (struct hostent *) NULL) {
1062: syslog(LOG_ERR,
1063: "unable to get network name for local machine %s",
1064: name);
1065: goto localcheck_done;
1066: } else strcpy(name, hp->h_name);
1067:
1068: /* get the standard network name of RM */
1069: hp = gethostbyname(RM);
1070: if (hp == (struct hostent *) NULL) {
1071: syslog(LOG_ERR,
1072: "unable to get hostname for remote machine %s", RM);
1073: goto localcheck_done;
1074: }
1075:
1076: /* if printer is not on local machine, ignore LP */
1077: if (strcmp(name, hp->h_name) != 0) *LP = '\0';
1078: }
1079: localcheck_done:
1080:
1081: AF = pgetstr("af", &bp);
1082: OF = pgetstr("of", &bp);
1083: IF = pgetstr("if", &bp);
1084: RF = pgetstr("rf", &bp);
1085: TF = pgetstr("tf", &bp);
1086: NF = pgetstr("nf", &bp);
1087: DF = pgetstr("df", &bp);
1088: GF = pgetstr("gf", &bp);
1089: VF = pgetstr("vf", &bp);
1090: CF = pgetstr("cf", &bp);
1091: TR = pgetstr("tr", &bp);
1092: RS = pgetflag("rs");
1093: SF = pgetflag("sf");
1094: SH = pgetflag("sh");
1095: SB = pgetflag("sb");
1096: HL = pgetflag("hl");
1097: RW = pgetflag("rw");
1098: BR = pgetnum("br");
1099: if ((FC = pgetnum("fc")) < 0)
1100: FC = 0;
1101: if ((FS = pgetnum("fs")) < 0)
1102: FS = 0;
1103: if ((XC = pgetnum("xc")) < 0)
1104: XC = 0;
1105: if ((XS = pgetnum("xs")) < 0)
1106: XS = 0;
1107: tof = !pgetflag("fo");
1108: }
1109:
1110: /*
1111: * Acquire line printer or remote connection.
1112: */
1113: openpr()
1114: {
1115: register int i, n;
1116: int resp;
1117:
1118: if (*LP) {
1119: for (i = 1; ; i = i < 32 ? i << 1 : i) {
1120: pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1121: if (pfd >= 0)
1122: break;
1123: if (errno == ENOENT) {
1124: syslog(LOG_ERR, "%s: %m", LP);
1125: exit(1);
1126: }
1127: if (i == 1)
1128: status("waiting for %s to become ready (offline ?)", printer);
1129: sleep(i);
1130: }
1131: if (isatty(pfd))
1132: setty();
1133: status("%s is ready and printing", printer);
1134: } else if (RM != NULL) {
1135: for (i = 1; ; i = i < 256 ? i << 1 : i) {
1136: resp = -1;
1137: pfd = getport(RM);
1138: if (pfd >= 0) {
1139: (void) sprintf(line, "\2%s\n", RP);
1140: n = strlen(line);
1141: if (write(pfd, line, n) == n &&
1142: (resp = response()) == '\0')
1143: break;
1144: (void) close(pfd);
1145: }
1146: if (i == 1) {
1147: if (resp < 0)
1148: status("waiting for %s to come up", RM);
1149: else {
1150: status("waiting for queue to be enabled on %s", RM);
1151: i = 256;
1152: }
1153: }
1154: sleep(i);
1155: }
1156: status("sending to %s", RM);
1157: remote = 1;
1158: } else {
1159: syslog(LOG_ERR, "%s: no line printer device or host name",
1160: printer);
1161: exit(1);
1162: }
1163: /*
1164: * Start up an output filter, if needed.
1165: */
1166: if (OF) {
1167: int p[2];
1168: char *cp;
1169:
1170: pipe(p);
1171: if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1172: dup2(p[0], 0); /* pipe is std in */
1173: dup2(pfd, 1); /* printer is std out */
1174: for (i = 3; i < NOFILE; i++)
1175: (void) close(i);
1176: if ((cp = rindex(OF, '/')) == NULL)
1177: cp = OF;
1178: else
1179: cp++;
1180: execl(OF, cp, width, length, 0);
1181: syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1182: exit(1);
1183: }
1184: (void) close(p[0]); /* close input side */
1185: ofd = p[1]; /* use pipe for output */
1186: } else {
1187: ofd = pfd;
1188: ofilter = 0;
1189: }
1190: }
1191:
1192: struct bauds {
1193: int baud;
1194: int speed;
1195: } bauds[] = {
1196: 50, B50,
1197: 75, B75,
1198: 110, B110,
1199: 134, B134,
1200: 150, B150,
1201: 200, B200,
1202: 300, B300,
1203: 600, B600,
1204: 1200, B1200,
1205: 1800, B1800,
1206: 2400, B2400,
1207: 4800, B4800,
1208: 9600, B9600,
1209: 19200, EXTA,
1210: 38400, EXTB,
1211: 0, 0
1212: };
1213:
1214: /*
1215: * setup tty lines.
1216: */
1217: setty()
1218: {
1219: struct sgttyb ttybuf;
1220: register struct bauds *bp;
1221:
1222: if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1223: syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1224: exit(1);
1225: }
1226: if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
1227: syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
1228: exit(1);
1229: }
1230: if (BR > 0) {
1231: for (bp = bauds; bp->baud; bp++)
1232: if (BR == bp->baud)
1233: break;
1234: if (!bp->baud) {
1235: syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1236: exit(1);
1237: }
1238: ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
1239: }
1240: ttybuf.sg_flags &= ~FC;
1241: ttybuf.sg_flags |= FS;
1242: if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
1243: syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
1244: exit(1);
1245: }
1246: if (XC || XS) {
1247: int ldisc = NTTYDISC;
1248:
1249: if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
1250: syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
1251: exit(1);
1252: }
1253: }
1254: if (XC) {
1255: if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
1256: syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
1257: exit(1);
1258: }
1259: }
1260: if (XS) {
1261: if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
1262: syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
1263: exit(1);
1264: }
1265: }
1266: }
1267:
1268: /*VARARGS1*/
1269: status(msg, a1, a2, a3)
1270: char *msg;
1271: {
1272: register int fd;
1273: char buf[BUFSIZ];
1274:
1275: umask(0);
1276: fd = open(ST, O_WRONLY|O_CREAT, 0664);
1277: if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1278: syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1279: exit(1);
1280: }
1281: ftruncate(fd, 0);
1282: sprintf(buf, msg, a1, a2, a3);
1283: strcat(buf, "\n");
1284: (void) write(fd, buf, strlen(buf));
1285: (void) close(fd);
1286: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.