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