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