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