printjob.c revision 1.1 1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)printjob.c 5.13 (Berkeley) 3/2/91";
36 #endif /* not lint */
37
38 /*
39 * printjob -- print jobs in the queue.
40 *
41 * NOTE: the lock file is used to pass information to lpq and lprm.
42 * it does not need to be removed because file locks are dynamic.
43 */
44
45 #include "lp.h"
46 #include "pathnames.h"
47
48 #define DORETURN 0 /* absorb fork error */
49 #define DOABORT 1 /* abort if dofork fails */
50
51 /*
52 * Error tokens
53 */
54 #define REPRINT -2
55 #define ERROR -1
56 #define OK 0
57 #define FATALERR 1
58 #define NOACCT 2
59 #define FILTERERR 3
60 #define ACCESS 4
61
62 char title[80]; /* ``pr'' title */
63 FILE *cfp; /* control file */
64 int pfd; /* printer file descriptor */
65 int ofd; /* output filter file descriptor */
66 int lfd; /* lock file descriptor */
67 int pid; /* pid of lpd process */
68 int prchild; /* id of pr process */
69 int child; /* id of any filters */
70 int ofilter; /* id of output filter, if any */
71 int tof; /* true if at top of form */
72 int remote; /* true if sending files to remote */
73 dev_t fdev; /* device of file pointed to by symlink */
74 ino_t fino; /* inode of file pointed to by symlink */
75
76 char fromhost[32]; /* user's host machine */
77 char logname[32]; /* user's login name */
78 char jobname[100]; /* job or file name */
79 char class[32]; /* classification field */
80 char width[10] = "-w"; /* page width in characters */
81 char length[10] = "-l"; /* page length in lines */
82 char pxwidth[10] = "-x"; /* page width in pixels */
83 char pxlength[10] = "-y"; /* page length in pixels */
84 char indent[10] = "-i0"; /* indentation size in characters */
85 char tempfile[] = "errsXXXXXX"; /* file name for filter output */
86
87 printjob()
88 {
89 struct stat stb;
90 register struct queue *q, **qp;
91 struct queue **queue;
92 register int i, nitems;
93 long pidoff;
94 int count = 0;
95 void abortpr();
96
97 init(); /* set up capabilities */
98 (void) write(1, "", 1); /* ack that daemon is started */
99 (void) close(2); /* set up log file */
100 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
101 syslog(LOG_ERR, "%s: %m", LF);
102 (void) open(_PATH_DEVNULL, O_WRONLY);
103 }
104 setgid(getegid());
105 pid = getpid(); /* for use with lprm */
106 setpgrp(0, pid);
107 signal(SIGHUP, abortpr);
108 signal(SIGINT, abortpr);
109 signal(SIGQUIT, abortpr);
110 signal(SIGTERM, abortpr);
111
112 (void) mktemp(tempfile);
113
114 /*
115 * uses short form file names
116 */
117 if (chdir(SD) < 0) {
118 syslog(LOG_ERR, "%s: %m", SD);
119 exit(1);
120 }
121 if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
122 exit(0); /* printing disabled */
123 lfd = open(LO, O_WRONLY|O_CREAT, 0644);
124 if (lfd < 0) {
125 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
126 exit(1);
127 }
128 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
129 if (errno == EWOULDBLOCK) /* active deamon present */
130 exit(0);
131 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
132 exit(1);
133 }
134 ftruncate(lfd, 0);
135 /*
136 * write process id for others to know
137 */
138 sprintf(line, "%u\n", pid);
139 pidoff = i = strlen(line);
140 if (write(lfd, line, i) != i) {
141 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
142 exit(1);
143 }
144 /*
145 * search the spool directory for work and sort by queue order.
146 */
147 if ((nitems = getq(&queue)) < 0) {
148 syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
149 exit(1);
150 }
151 if (nitems == 0) /* no work to do */
152 exit(0);
153 if (stb.st_mode & 01) { /* reset queue flag */
154 if (fchmod(lfd, stb.st_mode & 0776) < 0)
155 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
156 }
157 openpr(); /* open printer or remote */
158 again:
159 /*
160 * we found something to do now do it --
161 * write the name of the current control file into the lock file
162 * so the spool queue program can tell what we're working on
163 */
164 for (qp = queue; nitems--; free((char *) q)) {
165 q = *qp++;
166 if (stat(q->q_name, &stb) < 0)
167 continue;
168 restart:
169 (void) lseek(lfd, pidoff, 0);
170 (void) sprintf(line, "%s\n", q->q_name);
171 i = strlen(line);
172 if (write(lfd, line, i) != i)
173 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
174 if (!remote)
175 i = printit(q->q_name);
176 else
177 i = sendit(q->q_name);
178 /*
179 * Check to see if we are supposed to stop printing or
180 * if we are to rebuild the queue.
181 */
182 if (fstat(lfd, &stb) == 0) {
183 /* stop printing before starting next job? */
184 if (stb.st_mode & 0100)
185 goto done;
186 /* rebuild queue (after lpc topq) */
187 if (stb.st_mode & 01) {
188 for (free((char *) q); nitems--; free((char *) q))
189 q = *qp++;
190 if (fchmod(lfd, stb.st_mode & 0776) < 0)
191 syslog(LOG_WARNING, "%s: %s: %m",
192 printer, LO);
193 break;
194 }
195 }
196 if (i == OK) /* file ok and printed */
197 count++;
198 else if (i == REPRINT) { /* try reprinting the job */
199 syslog(LOG_INFO, "restarting %s", printer);
200 if (ofilter > 0) {
201 kill(ofilter, SIGCONT); /* to be sure */
202 (void) close(ofd);
203 while ((i = wait(0)) > 0 && i != ofilter)
204 ;
205 ofilter = 0;
206 }
207 (void) close(pfd); /* close printer */
208 if (ftruncate(lfd, pidoff) < 0)
209 syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
210 openpr(); /* try to reopen printer */
211 goto restart;
212 }
213 }
214 free((char *) queue);
215 /*
216 * search the spool directory for more work.
217 */
218 if ((nitems = getq(&queue)) < 0) {
219 syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
220 exit(1);
221 }
222 if (nitems == 0) { /* no more work to do */
223 done:
224 if (count > 0) { /* Files actually printed */
225 if (!SF && !tof)
226 (void) write(ofd, FF, strlen(FF));
227 if (TR != NULL) /* output trailer */
228 (void) write(ofd, TR, strlen(TR));
229 }
230 (void) unlink(tempfile);
231 exit(0);
232 }
233 goto again;
234 }
235
236 char fonts[4][50]; /* fonts for troff */
237
238 char ifonts[4][40] = {
239 _PATH_VFONTR,
240 _PATH_VFONTI,
241 _PATH_VFONTB,
242 _PATH_VFONTS,
243 };
244
245 /*
246 * The remaining part is the reading of the control file (cf)
247 * and performing the various actions.
248 */
249 printit(file)
250 char *file;
251 {
252 register int i;
253 char *cp;
254 int bombed = OK;
255
256 /*
257 * open control file; ignore if no longer there.
258 */
259 if ((cfp = fopen(file, "r")) == NULL) {
260 syslog(LOG_INFO, "%s: %s: %m", printer, file);
261 return(OK);
262 }
263 /*
264 * Reset troff fonts.
265 */
266 for (i = 0; i < 4; i++)
267 strcpy(fonts[i], ifonts[i]);
268 strcpy(width+2, "0");
269 strcpy(indent+2, "0");
270
271 /*
272 * read the control file for work to do
273 *
274 * file format -- first character in the line is a command
275 * rest of the line is the argument.
276 * valid commands are:
277 *
278 * S -- "stat info" for symbolic link protection
279 * J -- "job name" on banner page
280 * C -- "class name" on banner page
281 * L -- "literal" user's name to print on banner
282 * T -- "title" for pr
283 * H -- "host name" of machine where lpr was done
284 * P -- "person" user's login name
285 * I -- "indent" amount to indent output
286 * f -- "file name" name of text file to print
287 * l -- "file name" text file with control chars
288 * p -- "file name" text file to print with pr(1)
289 * t -- "file name" troff(1) file to print
290 * n -- "file name" ditroff(1) file to print
291 * d -- "file name" dvi file to print
292 * g -- "file name" plot(1G) file to print
293 * v -- "file name" plain raster file to print
294 * c -- "file name" cifplot file to print
295 * 1 -- "R font file" for troff
296 * 2 -- "I font file" for troff
297 * 3 -- "B font file" for troff
298 * 4 -- "S font file" for troff
299 * N -- "name" of file (used by lpq)
300 * U -- "unlink" name of file to remove
301 * (after we print it. (Pass 2 only)).
302 * M -- "mail" to user when done printing
303 *
304 * getline reads a line and expands tabs to blanks
305 */
306
307 /* pass 1 */
308
309 while (getline(cfp))
310 switch (line[0]) {
311 case 'H':
312 strcpy(fromhost, line+1);
313 if (class[0] == '\0')
314 strncpy(class, line+1, sizeof(class)-1);
315 continue;
316
317 case 'P':
318 strncpy(logname, line+1, sizeof(logname)-1);
319 if (RS) { /* restricted */
320 if (getpwnam(logname) == (struct passwd *)0) {
321 bombed = NOACCT;
322 sendmail(line+1, bombed);
323 goto pass2;
324 }
325 }
326 continue;
327
328 case 'S':
329 cp = line+1;
330 i = 0;
331 while (*cp >= '0' && *cp <= '9')
332 i = i * 10 + (*cp++ - '0');
333 fdev = i;
334 cp++;
335 i = 0;
336 while (*cp >= '0' && *cp <= '9')
337 i = i * 10 + (*cp++ - '0');
338 fino = i;
339 continue;
340
341 case 'J':
342 if (line[1] != '\0')
343 strncpy(jobname, line+1, sizeof(jobname)-1);
344 else
345 strcpy(jobname, " ");
346 continue;
347
348 case 'C':
349 if (line[1] != '\0')
350 strncpy(class, line+1, sizeof(class)-1);
351 else if (class[0] == '\0')
352 gethostname(class, sizeof(class));
353 continue;
354
355 case 'T': /* header title for pr */
356 strncpy(title, line+1, sizeof(title)-1);
357 continue;
358
359 case 'L': /* identification line */
360 if (!SH && !HL)
361 banner(line+1, jobname);
362 continue;
363
364 case '1': /* troff fonts */
365 case '2':
366 case '3':
367 case '4':
368 if (line[1] != '\0')
369 strcpy(fonts[line[0]-'1'], line+1);
370 continue;
371
372 case 'W': /* page width */
373 strncpy(width+2, line+1, sizeof(width)-3);
374 continue;
375
376 case 'I': /* indent amount */
377 strncpy(indent+2, line+1, sizeof(indent)-3);
378 continue;
379
380 default: /* some file to print */
381 switch (i = print(line[0], line+1)) {
382 case ERROR:
383 if (bombed == OK)
384 bombed = FATALERR;
385 break;
386 case REPRINT:
387 (void) fclose(cfp);
388 return(REPRINT);
389 case FILTERERR:
390 case ACCESS:
391 bombed = i;
392 sendmail(logname, bombed);
393 }
394 title[0] = '\0';
395 continue;
396
397 case 'N':
398 case 'U':
399 case 'M':
400 continue;
401 }
402
403 /* pass 2 */
404
405 pass2:
406 fseek(cfp, 0L, 0);
407 while (getline(cfp))
408 switch (line[0]) {
409 case 'L': /* identification line */
410 if (!SH && HL)
411 banner(line+1, jobname);
412 continue;
413
414 case 'M':
415 if (bombed < NOACCT) /* already sent if >= NOACCT */
416 sendmail(line+1, bombed);
417 continue;
418
419 case 'U':
420 (void) unlink(line+1);
421 }
422 /*
423 * clean-up in case another control file exists
424 */
425 (void) fclose(cfp);
426 (void) unlink(file);
427 return(bombed == OK ? OK : ERROR);
428 }
429
430 /*
431 * Print a file.
432 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
433 * Return -1 if a non-recoverable error occured,
434 * 2 if the filter detected some errors (but printed the job anyway),
435 * 1 if we should try to reprint this job and
436 * 0 if all is well.
437 * Note: all filters take stdin as the file, stdout as the printer,
438 * stderr as the log file, and must not ignore SIGINT.
439 */
440 print(format, file)
441 int format;
442 char *file;
443 {
444 register int n;
445 register char *prog;
446 int fi, fo;
447 FILE *fp;
448 char *av[15], buf[BUFSIZ];
449 int pid, p[2], stopped = 0;
450 union wait status;
451 struct stat stb;
452
453 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
454 return(ERROR);
455 /*
456 * Check to see if data file is a symbolic link. If so, it should
457 * still point to the same file or someone is trying to print
458 * something he shouldn't.
459 */
460 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
461 (stb.st_dev != fdev || stb.st_ino != fino))
462 return(ACCESS);
463 if (!SF && !tof) { /* start on a fresh page */
464 (void) write(ofd, FF, strlen(FF));
465 tof = 1;
466 }
467 if (IF == NULL && (format == 'f' || format == 'l')) {
468 tof = 0;
469 while ((n = read(fi, buf, BUFSIZ)) > 0)
470 if (write(ofd, buf, n) != n) {
471 (void) close(fi);
472 return(REPRINT);
473 }
474 (void) close(fi);
475 return(OK);
476 }
477 switch (format) {
478 case 'p': /* print file using 'pr' */
479 if (IF == NULL) { /* use output filter */
480 prog = _PATH_PR;
481 av[0] = "pr";
482 av[1] = width;
483 av[2] = length;
484 av[3] = "-h";
485 av[4] = *title ? title : " ";
486 av[5] = 0;
487 fo = ofd;
488 goto start;
489 }
490 pipe(p);
491 if ((prchild = dofork(DORETURN)) == 0) { /* child */
492 dup2(fi, 0); /* file is stdin */
493 dup2(p[1], 1); /* pipe is stdout */
494 for (n = 3; n < NOFILE; n++)
495 (void) close(n);
496 execl(_PATH_PR, "pr", width, length,
497 "-h", *title ? title : " ", 0);
498 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
499 exit(2);
500 }
501 (void) close(p[1]); /* close output side */
502 (void) close(fi);
503 if (prchild < 0) {
504 prchild = 0;
505 (void) close(p[0]);
506 return(ERROR);
507 }
508 fi = p[0]; /* use pipe for input */
509 case 'f': /* print plain text file */
510 prog = IF;
511 av[1] = width;
512 av[2] = length;
513 av[3] = indent;
514 n = 4;
515 break;
516 case 'l': /* like 'f' but pass control characters */
517 prog = IF;
518 av[1] = "-c";
519 av[2] = width;
520 av[3] = length;
521 av[4] = indent;
522 n = 5;
523 break;
524 case 'r': /* print a fortran text file */
525 prog = RF;
526 av[1] = width;
527 av[2] = length;
528 n = 3;
529 break;
530 case 't': /* print troff output */
531 case 'n': /* print ditroff output */
532 case 'd': /* print tex output */
533 (void) unlink(".railmag");
534 if ((fo = creat(".railmag", FILMOD)) < 0) {
535 syslog(LOG_ERR, "%s: cannot create .railmag", printer);
536 (void) unlink(".railmag");
537 } else {
538 for (n = 0; n < 4; n++) {
539 if (fonts[n][0] != '/')
540 (void) write(fo, _PATH_VFONT, 15);
541 (void) write(fo, fonts[n], strlen(fonts[n]));
542 (void) write(fo, "\n", 1);
543 }
544 (void) close(fo);
545 }
546 prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
547 av[1] = pxwidth;
548 av[2] = pxlength;
549 n = 3;
550 break;
551 case 'c': /* print cifplot output */
552 prog = CF;
553 av[1] = pxwidth;
554 av[2] = pxlength;
555 n = 3;
556 break;
557 case 'g': /* print plot(1G) output */
558 prog = GF;
559 av[1] = pxwidth;
560 av[2] = pxlength;
561 n = 3;
562 break;
563 case 'v': /* print raster output */
564 prog = VF;
565 av[1] = pxwidth;
566 av[2] = pxlength;
567 n = 3;
568 break;
569 default:
570 (void) close(fi);
571 syslog(LOG_ERR, "%s: illegal format character '%c'",
572 printer, format);
573 return(ERROR);
574 }
575 if ((av[0] = rindex(prog, '/')) != NULL)
576 av[0]++;
577 else
578 av[0] = prog;
579 av[n++] = "-n";
580 av[n++] = logname;
581 av[n++] = "-h";
582 av[n++] = fromhost;
583 av[n++] = AF;
584 av[n] = 0;
585 fo = pfd;
586 if (ofilter > 0) { /* stop output filter */
587 write(ofd, "\031\1", 2);
588 while ((pid =
589 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
590 ;
591 if (status.w_stopval != WSTOPPED) {
592 (void) close(fi);
593 syslog(LOG_WARNING, "%s: output filter died (%d)",
594 printer, status.w_retcode);
595 return(REPRINT);
596 }
597 stopped++;
598 }
599 start:
600 if ((child = dofork(DORETURN)) == 0) { /* child */
601 dup2(fi, 0);
602 dup2(fo, 1);
603 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
604 if (n >= 0)
605 dup2(n, 2);
606 for (n = 3; n < NOFILE; n++)
607 (void) close(n);
608 execv(prog, av);
609 syslog(LOG_ERR, "cannot execv %s", prog);
610 exit(2);
611 }
612 (void) close(fi);
613 if (child < 0)
614 status.w_retcode = 100;
615 else
616 while ((pid = wait((int *)&status)) > 0 && pid != child)
617 ;
618 child = 0;
619 prchild = 0;
620 if (stopped) { /* restart output filter */
621 if (kill(ofilter, SIGCONT) < 0) {
622 syslog(LOG_ERR, "cannot restart output filter");
623 exit(1);
624 }
625 }
626 tof = 0;
627
628 /* Copy filter output to "lf" logfile */
629 if (fp = fopen(tempfile, "r")) {
630 char tbuf[512];
631
632 while (fgets(buf, sizeof(buf), fp))
633 fputs(buf, stderr);
634 close(fp);
635 }
636
637 if (!WIFEXITED(status)) {
638 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
639 printer, format, status.w_termsig);
640 return(ERROR);
641 }
642 switch (status.w_retcode) {
643 case 0:
644 tof = 1;
645 return(OK);
646 case 1:
647 return(REPRINT);
648 default:
649 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
650 printer, format, status.w_retcode);
651 case 2:
652 return(ERROR);
653 }
654 }
655
656 /*
657 * Send the daemon control file (cf) and any data files.
658 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
659 * 0 if all is well.
660 */
661 sendit(file)
662 char *file;
663 {
664 register int i, err = OK;
665 char *cp, last[BUFSIZ];
666
667 /*
668 * open control file
669 */
670 if ((cfp = fopen(file, "r")) == NULL)
671 return(OK);
672 /*
673 * read the control file for work to do
674 *
675 * file format -- first character in the line is a command
676 * rest of the line is the argument.
677 * commands of interest are:
678 *
679 * a-z -- "file name" name of file to print
680 * U -- "unlink" name of file to remove
681 * (after we print it. (Pass 2 only)).
682 */
683
684 /*
685 * pass 1
686 */
687 while (getline(cfp)) {
688 again:
689 if (line[0] == 'S') {
690 cp = line+1;
691 i = 0;
692 while (*cp >= '0' && *cp <= '9')
693 i = i * 10 + (*cp++ - '0');
694 fdev = i;
695 cp++;
696 i = 0;
697 while (*cp >= '0' && *cp <= '9')
698 i = i * 10 + (*cp++ - '0');
699 fino = i;
700 continue;
701 }
702 if (line[0] >= 'a' && line[0] <= 'z') {
703 strcpy(last, line);
704 while (i = getline(cfp))
705 if (strcmp(last, line))
706 break;
707 switch (sendfile('\3', last+1)) {
708 case OK:
709 if (i)
710 goto again;
711 break;
712 case REPRINT:
713 (void) fclose(cfp);
714 return(REPRINT);
715 case ACCESS:
716 sendmail(logname, ACCESS);
717 case ERROR:
718 err = ERROR;
719 }
720 break;
721 }
722 }
723 if (err == OK && sendfile('\2', file) > 0) {
724 (void) fclose(cfp);
725 return(REPRINT);
726 }
727 /*
728 * pass 2
729 */
730 fseek(cfp, 0L, 0);
731 while (getline(cfp))
732 if (line[0] == 'U')
733 (void) unlink(line+1);
734 /*
735 * clean-up in case another control file exists
736 */
737 (void) fclose(cfp);
738 (void) unlink(file);
739 return(err);
740 }
741
742 /*
743 * Send a data file to the remote machine and spool it.
744 * Return positive if we should try resending.
745 */
746 sendfile(type, file)
747 char type, *file;
748 {
749 register int f, i, amt;
750 struct stat stb;
751 char buf[BUFSIZ];
752 int sizerr, resp;
753
754 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
755 return(ERROR);
756 /*
757 * Check to see if data file is a symbolic link. If so, it should
758 * still point to the same file or someone is trying to print something
759 * he shouldn't.
760 */
761 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
762 (stb.st_dev != fdev || stb.st_ino != fino))
763 return(ACCESS);
764 (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
765 amt = strlen(buf);
766 for (i = 0; ; i++) {
767 if (write(pfd, buf, amt) != amt ||
768 (resp = response()) < 0 || resp == '\1') {
769 (void) close(f);
770 return(REPRINT);
771 } else if (resp == '\0')
772 break;
773 if (i == 0)
774 status("no space on remote; waiting for queue to drain");
775 if (i == 10)
776 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
777 printer, RM);
778 sleep(5 * 60);
779 }
780 if (i)
781 status("sending to %s", RM);
782 sizerr = 0;
783 for (i = 0; i < stb.st_size; i += BUFSIZ) {
784 amt = BUFSIZ;
785 if (i + amt > stb.st_size)
786 amt = stb.st_size - i;
787 if (sizerr == 0 && read(f, buf, amt) != amt)
788 sizerr = 1;
789 if (write(pfd, buf, amt) != amt) {
790 (void) close(f);
791 return(REPRINT);
792 }
793 }
794 (void) close(f);
795 if (sizerr) {
796 syslog(LOG_INFO, "%s: %s: changed size", printer, file);
797 /* tell recvjob to ignore this file */
798 (void) write(pfd, "\1", 1);
799 return(ERROR);
800 }
801 if (write(pfd, "", 1) != 1 || response())
802 return(REPRINT);
803 return(OK);
804 }
805
806 /*
807 * Check to make sure there have been no errors and that both programs
808 * are in sync with eachother.
809 * Return non-zero if the connection was lost.
810 */
811 response()
812 {
813 char resp;
814
815 if (read(pfd, &resp, 1) != 1) {
816 syslog(LOG_INFO, "%s: lost connection", printer);
817 return(-1);
818 }
819 return(resp);
820 }
821
822 /*
823 * Banner printing stuff
824 */
825 banner(name1, name2)
826 char *name1, *name2;
827 {
828 time_t tvec;
829 extern char *ctime();
830
831 time(&tvec);
832 if (!SF && !tof)
833 (void) write(ofd, FF, strlen(FF));
834 if (SB) { /* short banner only */
835 if (class[0]) {
836 (void) write(ofd, class, strlen(class));
837 (void) write(ofd, ":", 1);
838 }
839 (void) write(ofd, name1, strlen(name1));
840 (void) write(ofd, " Job: ", 7);
841 (void) write(ofd, name2, strlen(name2));
842 (void) write(ofd, " Date: ", 8);
843 (void) write(ofd, ctime(&tvec), 24);
844 (void) write(ofd, "\n", 1);
845 } else { /* normal banner */
846 (void) write(ofd, "\n\n\n", 3);
847 scan_out(ofd, name1, '\0');
848 (void) write(ofd, "\n\n", 2);
849 scan_out(ofd, name2, '\0');
850 if (class[0]) {
851 (void) write(ofd,"\n\n\n",3);
852 scan_out(ofd, class, '\0');
853 }
854 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
855 (void) write(ofd, name2, strlen(name2));
856 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
857 (void) write(ofd, ctime(&tvec), 24);
858 (void) write(ofd, "\n", 1);
859 }
860 if (!SF)
861 (void) write(ofd, FF, strlen(FF));
862 tof = 1;
863 }
864
865 char *
866 scnline(key, p, c)
867 register char key, *p;
868 char c;
869 {
870 register scnwidth;
871
872 for (scnwidth = WIDTH; --scnwidth;) {
873 key <<= 1;
874 *p++ = key & 0200 ? c : BACKGND;
875 }
876 return (p);
877 }
878
879 #define TRC(q) (((q)-' ')&0177)
880
881 scan_out(scfd, scsp, dlm)
882 int scfd;
883 char *scsp, dlm;
884 {
885 register char *strp;
886 register nchrs, j;
887 char outbuf[LINELEN+1], *sp, c, cc;
888 int d, scnhgt;
889 extern char scnkey[][HEIGHT]; /* in lpdchar.c */
890
891 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
892 strp = &outbuf[0];
893 sp = scsp;
894 for (nchrs = 0; ; ) {
895 d = dropit(c = TRC(cc = *sp++));
896 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
897 for (j = WIDTH; --j;)
898 *strp++ = BACKGND;
899 else
900 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
901 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
902 break;
903 *strp++ = BACKGND;
904 *strp++ = BACKGND;
905 }
906 while (*--strp == BACKGND && strp >= outbuf)
907 ;
908 strp++;
909 *strp++ = '\n';
910 (void) write(scfd, outbuf, strp-outbuf);
911 }
912 }
913
914 dropit(c)
915 char c;
916 {
917 switch(c) {
918
919 case TRC('_'):
920 case TRC(';'):
921 case TRC(','):
922 case TRC('g'):
923 case TRC('j'):
924 case TRC('p'):
925 case TRC('q'):
926 case TRC('y'):
927 return (DROP);
928
929 default:
930 return (0);
931 }
932 }
933
934 /*
935 * sendmail ---
936 * tell people about job completion
937 */
938 sendmail(user, bombed)
939 char *user;
940 int bombed;
941 {
942 register int i;
943 int p[2], s;
944 register char *cp;
945 char buf[100];
946 struct stat stb;
947 FILE *fp;
948
949 pipe(p);
950 if ((s = dofork(DORETURN)) == 0) { /* child */
951 dup2(p[0], 0);
952 for (i = 3; i < NOFILE; i++)
953 (void) close(i);
954 if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
955 cp++;
956 else
957 cp = _PATH_SENDMAIL;
958 sprintf(buf, "%s@%s", user, fromhost);
959 execl(_PATH_SENDMAIL, cp, buf, 0);
960 exit(0);
961 } else if (s > 0) { /* parent */
962 dup2(p[1], 1);
963 printf("To: %s@%s\n", user, fromhost);
964 printf("Subject: printer job\n\n");
965 printf("Your printer job ");
966 if (*jobname)
967 printf("(%s) ", jobname);
968 switch (bombed) {
969 case OK:
970 printf("\ncompleted successfully\n");
971 break;
972 default:
973 case FATALERR:
974 printf("\ncould not be printed\n");
975 break;
976 case NOACCT:
977 printf("\ncould not be printed without an account on %s\n", host);
978 break;
979 case FILTERERR:
980 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
981 (fp = fopen(tempfile, "r")) == NULL) {
982 printf("\nwas printed but had some errors\n");
983 break;
984 }
985 printf("\nwas printed but had the following errors:\n");
986 while ((i = getc(fp)) != EOF)
987 putchar(i);
988 (void) fclose(fp);
989 break;
990 case ACCESS:
991 printf("\nwas not printed because it was not linked to the original file\n");
992 }
993 fflush(stdout);
994 (void) close(1);
995 }
996 (void) close(p[0]);
997 (void) close(p[1]);
998 wait(&s);
999 }
1000
1001 /*
1002 * dofork - fork with retries on failure
1003 */
1004 dofork(action)
1005 int action;
1006 {
1007 register int i, pid;
1008
1009 for (i = 0; i < 20; i++) {
1010 if ((pid = fork()) < 0) {
1011 sleep((unsigned)(i*i));
1012 continue;
1013 }
1014 /*
1015 * Child should run as daemon instead of root
1016 */
1017 if (pid == 0)
1018 setuid(DU);
1019 return(pid);
1020 }
1021 syslog(LOG_ERR, "can't fork");
1022
1023 switch (action) {
1024 case DORETURN:
1025 return (-1);
1026 default:
1027 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1028 /*FALL THRU*/
1029 case DOABORT:
1030 exit(1);
1031 }
1032 /*NOTREACHED*/
1033 }
1034
1035 /*
1036 * Kill child processes to abort current job.
1037 */
1038 void
1039 abortpr()
1040 {
1041 (void) unlink(tempfile);
1042 kill(0, SIGINT);
1043 if (ofilter > 0)
1044 kill(ofilter, SIGCONT);
1045 while (wait(NULL) > 0)
1046 ;
1047 exit(0);
1048 }
1049
1050 init()
1051 {
1052 int status;
1053 char *s;
1054
1055 if ((status = pgetent(line, printer)) < 0) {
1056 syslog(LOG_ERR, "can't open printer description file");
1057 exit(1);
1058 } else if (status == 0) {
1059 syslog(LOG_ERR, "unknown printer: %s", printer);
1060 exit(1);
1061 }
1062 if ((LP = pgetstr("lp", &bp)) == NULL)
1063 LP = _PATH_DEFDEVLP;
1064 if ((RP = pgetstr("rp", &bp)) == NULL)
1065 RP = DEFLP;
1066 if ((LO = pgetstr("lo", &bp)) == NULL)
1067 LO = DEFLOCK;
1068 if ((ST = pgetstr("st", &bp)) == NULL)
1069 ST = DEFSTAT;
1070 if ((LF = pgetstr("lf", &bp)) == NULL)
1071 LF = _PATH_CONSOLE;
1072 if ((SD = pgetstr("sd", &bp)) == NULL)
1073 SD = _PATH_DEFSPOOL;
1074 if ((DU = pgetnum("du")) < 0)
1075 DU = DEFUID;
1076 if ((FF = pgetstr("ff", &bp)) == NULL)
1077 FF = DEFFF;
1078 if ((PW = pgetnum("pw")) < 0)
1079 PW = DEFWIDTH;
1080 sprintf(&width[2], "%d", PW);
1081 if ((PL = pgetnum("pl")) < 0)
1082 PL = DEFLENGTH;
1083 sprintf(&length[2], "%d", PL);
1084 if ((PX = pgetnum("px")) < 0)
1085 PX = 0;
1086 sprintf(&pxwidth[2], "%d", PX);
1087 if ((PY = pgetnum("py")) < 0)
1088 PY = 0;
1089 sprintf(&pxlength[2], "%d", PY);
1090 RM = pgetstr("rm", &bp);
1091 if (s = checkremote())
1092 syslog(LOG_WARNING, s);
1093
1094 AF = pgetstr("af", &bp);
1095 OF = pgetstr("of", &bp);
1096 IF = pgetstr("if", &bp);
1097 RF = pgetstr("rf", &bp);
1098 TF = pgetstr("tf", &bp);
1099 NF = pgetstr("nf", &bp);
1100 DF = pgetstr("df", &bp);
1101 GF = pgetstr("gf", &bp);
1102 VF = pgetstr("vf", &bp);
1103 CF = pgetstr("cf", &bp);
1104 TR = pgetstr("tr", &bp);
1105 RS = pgetflag("rs");
1106 SF = pgetflag("sf");
1107 SH = pgetflag("sh");
1108 SB = pgetflag("sb");
1109 HL = pgetflag("hl");
1110 RW = pgetflag("rw");
1111 BR = pgetnum("br");
1112 if ((FC = pgetnum("fc")) < 0)
1113 FC = 0;
1114 if ((FS = pgetnum("fs")) < 0)
1115 FS = 0;
1116 if ((XC = pgetnum("xc")) < 0)
1117 XC = 0;
1118 if ((XS = pgetnum("xs")) < 0)
1119 XS = 0;
1120 tof = !pgetflag("fo");
1121 }
1122
1123 /*
1124 * Acquire line printer or remote connection.
1125 */
1126 openpr()
1127 {
1128 register int i, n;
1129 int resp;
1130
1131 if (!sendtorem && *LP) {
1132 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1133 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1134 if (pfd >= 0)
1135 break;
1136 if (errno == ENOENT) {
1137 syslog(LOG_ERR, "%s: %m", LP);
1138 exit(1);
1139 }
1140 if (i == 1)
1141 status("waiting for %s to become ready (offline ?)", printer);
1142 sleep(i);
1143 }
1144 if (isatty(pfd))
1145 setty();
1146 status("%s is ready and printing", printer);
1147 } else if (RM != NULL) {
1148 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1149 resp = -1;
1150 pfd = getport(RM);
1151 if (pfd >= 0) {
1152 (void) sprintf(line, "\2%s\n", RP);
1153 n = strlen(line);
1154 if (write(pfd, line, n) == n &&
1155 (resp = response()) == '\0')
1156 break;
1157 (void) close(pfd);
1158 }
1159 if (i == 1) {
1160 if (resp < 0)
1161 status("waiting for %s to come up", RM);
1162 else {
1163 status("waiting for queue to be enabled on %s", RM);
1164 i = 256;
1165 }
1166 }
1167 sleep(i);
1168 }
1169 status("sending to %s", RM);
1170 remote = 1;
1171 } else {
1172 syslog(LOG_ERR, "%s: no line printer device or host name",
1173 printer);
1174 exit(1);
1175 }
1176 /*
1177 * Start up an output filter, if needed.
1178 */
1179 if (!remote && OF) {
1180 int p[2];
1181 char *cp;
1182
1183 pipe(p);
1184 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1185 dup2(p[0], 0); /* pipe is std in */
1186 dup2(pfd, 1); /* printer is std out */
1187 for (i = 3; i < NOFILE; i++)
1188 (void) close(i);
1189 if ((cp = rindex(OF, '/')) == NULL)
1190 cp = OF;
1191 else
1192 cp++;
1193 execl(OF, cp, width, length, 0);
1194 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1195 exit(1);
1196 }
1197 (void) close(p[0]); /* close input side */
1198 ofd = p[1]; /* use pipe for output */
1199 } else {
1200 ofd = pfd;
1201 ofilter = 0;
1202 }
1203 }
1204
1205 struct bauds {
1206 int baud;
1207 int speed;
1208 } bauds[] = {
1209 50, B50,
1210 75, B75,
1211 110, B110,
1212 134, B134,
1213 150, B150,
1214 200, B200,
1215 300, B300,
1216 600, B600,
1217 1200, B1200,
1218 1800, B1800,
1219 2400, B2400,
1220 4800, B4800,
1221 9600, B9600,
1222 19200, EXTA,
1223 38400, EXTB,
1224 0, 0
1225 };
1226
1227 /*
1228 * setup tty lines.
1229 */
1230 setty()
1231 {
1232 struct sgttyb ttybuf;
1233 register struct bauds *bp;
1234
1235 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1236 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1237 exit(1);
1238 }
1239 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
1240 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
1241 exit(1);
1242 }
1243 if (BR > 0) {
1244 for (bp = bauds; bp->baud; bp++)
1245 if (BR == bp->baud)
1246 break;
1247 if (!bp->baud) {
1248 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1249 exit(1);
1250 }
1251 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
1252 }
1253 ttybuf.sg_flags &= ~FC;
1254 ttybuf.sg_flags |= FS;
1255 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
1256 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
1257 exit(1);
1258 }
1259 if (XC) {
1260 if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
1261 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
1262 exit(1);
1263 }
1264 }
1265 if (XS) {
1266 if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
1267 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
1268 exit(1);
1269 }
1270 }
1271 }
1272
1273 /*VARARGS1*/
1274 status(msg, a1, a2, a3)
1275 char *msg;
1276 {
1277 register int fd;
1278 char buf[BUFSIZ];
1279
1280 umask(0);
1281 fd = open(ST, O_WRONLY|O_CREAT, 0664);
1282 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1283 syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1284 exit(1);
1285 }
1286 ftruncate(fd, 0);
1287 sprintf(buf, msg, a1, a2, a3);
1288 strcat(buf, "\n");
1289 (void) write(fd, buf, strlen(buf));
1290 (void) close(fd);
1291 }
1292