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