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