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