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