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