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