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