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