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