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