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