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