printjob.c revision 1.34 1 /* $NetBSD: printjob.c,v 1.34 2002/07/14 15:28:00 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.34 2002/07/14 15:28:00 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; /* 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 width[10] = "-w"; /* page width in static characters */
121
122 static void abortpr(int);
123 static void banner(char *, char *);
124 static int dofork(int);
125 static int dropit(int);
126 static void init(void);
127 static void openpr(void);
128 static void opennet(char *);
129 static void opentty(void);
130 static void openrem(void);
131 static int print(int, char *);
132 static int printit(char *);
133 static void pstatus(const char *, ...)
134 __attribute__((__format__(__printf__, 1, 2)));
135 static char response(void);
136 static void scan_out(int, char *, int);
137 static char *scnline(int, char *, int);
138 static int sendfile(int, char *);
139 static int sendit(char *);
140 static void sendmail(char *, int);
141 static void setty(void);
142 static void alarmer(int);
143
144 void
145 printjob(void)
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(STDOUT_FILENO, "", 1); /* ack that daemon is started */
156 (void)close(STDERR_FILENO); /* 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 daemon 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 stb.st_mode &= ~S_IXOTH;
211 if (fchmod(lfd, stb.st_mode & 0777) < 0)
212 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
213 }
214 openpr(); /* open printer or remote */
215 again:
216 /*
217 * we found something to do now do it --
218 * write the name of the current control file into the lock file
219 * so the spool queue program can tell what we're working on
220 */
221 for (qp = queue; nitems--; free((char *) q)) {
222 q = *qp++;
223 if (stat(q->q_name, &stb) < 0)
224 continue;
225 errcnt = 0;
226 restart:
227 (void)lseek(lfd, pidoff, 0);
228 i = snprintf(line, sizeof(line), "%s\n", q->q_name);
229 if (write(lfd, line, i) != i)
230 syslog(LOG_ERR, "%s: %s: %m", printer, LO);
231 if (!remote)
232 i = printit(q->q_name);
233 else
234 i = sendit(q->q_name);
235 /*
236 * Check to see if we are supposed to stop printing or
237 * if we are to rebuild the queue.
238 */
239 if (fstat(lfd, &stb) == 0) {
240 /* stop printing before starting next job? */
241 if (stb.st_mode & S_IXUSR)
242 goto done;
243 /* rebuild queue (after lpc topq) */
244 if (stb.st_mode & S_IXOTH) {
245 for (free((char *) q); nitems--; free((char *) q))
246 q = *qp++;
247 stb.st_mode &= ~S_IXOTH;
248 if (fchmod(lfd, stb.st_mode & 0777) < 0)
249 syslog(LOG_WARNING, "%s: %s: %m",
250 printer, LO);
251 break;
252 }
253 }
254 if (i == OK) /* file ok and printed */
255 count++;
256 else if (i == REPRINT && ++errcnt < 5) {
257 /* try reprinting the job */
258 syslog(LOG_INFO, "restarting %s", printer);
259 if (ofilter > 0) {
260 kill(ofilter, SIGCONT); /* to be sure */
261 (void)close(ofd);
262 while ((i = wait(NULL)) > 0 && i != ofilter)
263 ;
264 ofilter = 0;
265 }
266 (void)close(pfd); /* close printer */
267 if (ftruncate(lfd, pidoff) < 0)
268 syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
269 openpr(); /* try to reopen printer */
270 goto restart;
271 } else {
272 syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
273 remote ? "sent to remote host" : "printed", q->q_name);
274 if (i == REPRINT) {
275 /* ensure we don't attempt this job again */
276 (void) unlink(q->q_name);
277 q->q_name[0] = 'd';
278 (void) unlink(q->q_name);
279 if (logname[0])
280 sendmail(logname, FATALERR);
281 }
282 }
283 }
284 free((char *) queue);
285 /*
286 * search the spool directory for more work.
287 */
288 if ((nitems = getq(&queue)) < 0) {
289 syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
290 exit(1);
291 }
292 if (nitems == 0) { /* no more work to do */
293 done:
294 if (count > 0) { /* Files actually printed */
295 if (!SF && !tof)
296 (void)write(ofd, FF, strlen(FF));
297 if (TR != NULL) /* output trailer */
298 (void)write(ofd, TR, strlen(TR));
299 }
300 (void)unlink(tempfile);
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 (termsig=%d)",
741 printer, format, 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
858 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
859 return(ERROR);
860 /*
861 * Check to see if data file is a symbolic link. If so, it should
862 * still point to the same file or someone is trying to print something
863 * he shouldn't.
864 */
865 if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
866 (stb.st_dev != fdev || stb.st_ino != fino))
867 return(ACCESS);
868 amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
869 (long long)stb.st_size, file);
870 for (i = 0; ; i++) {
871 if (write(pfd, buf, amt) != amt ||
872 (resp = response()) < 0 || resp == '\1') {
873 (void)close(f);
874 return(REPRINT);
875 } else if (resp == '\0')
876 break;
877 if (i == 0)
878 pstatus("no space on remote; waiting for queue to drain");
879 if (i == 10)
880 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
881 printer, RM);
882 sleep(5 * 60);
883 }
884 if (i)
885 pstatus("sending to %s", RM);
886 sizerr = 0;
887 for (i = 0; i < stb.st_size; i += BUFSIZ) {
888 struct sigaction osa, nsa;
889
890 amt = BUFSIZ;
891 if (i + amt > stb.st_size)
892 amt = stb.st_size - i;
893 if (sizerr == 0 && read(f, buf, amt) != amt)
894 sizerr = 1;
895 nsa.sa_handler = alarmer;
896 sigemptyset(&nsa.sa_mask);
897 sigaddset(&nsa.sa_mask, SIGALRM);
898 nsa.sa_flags = 0;
899 (void)sigaction(SIGALRM, &nsa, &osa);
900 alarm(wait_time);
901 if (write(pfd, buf, amt) != amt) {
902 alarm(0);
903 (void)sigaction(SIGALRM, &osa, NULL);
904 (void)close(f);
905 return(REPRINT);
906 }
907 alarm(0);
908 (void)sigaction(SIGALRM, &osa, NULL);
909 }
910
911 (void)close(f);
912 if (sizerr) {
913 syslog(LOG_INFO, "%s: %s: changed size", printer, file);
914 /* tell recvjob to ignore this file */
915 (void)write(pfd, "\1", 1);
916 return(ERROR);
917 }
918 if (write(pfd, "", 1) != 1 || response())
919 return(REPRINT);
920 return(OK);
921 }
922
923 /*
924 * Check to make sure there have been no errors and that both programs
925 * are in sync with eachother.
926 * Return non-zero if the connection was lost.
927 */
928 static char
929 response(void)
930 {
931 struct sigaction osa, nsa;
932 char resp;
933
934 nsa.sa_handler = alarmer;
935 sigemptyset(&nsa.sa_mask);
936 sigaddset(&nsa.sa_mask, SIGALRM);
937 nsa.sa_flags = 0;
938 (void)sigaction(SIGALRM, &nsa, &osa);
939 alarm(wait_time);
940 if (read(pfd, &resp, 1) != 1) {
941 syslog(LOG_INFO, "%s: lost connection", printer);
942 resp = -1;
943 }
944 alarm(0);
945 (void)sigaction(SIGALRM, &osa, NULL);
946 return (resp);
947 }
948
949 /*
950 * Banner printing stuff
951 */
952 static void
953 banner(char *name1, char *name2)
954 {
955 time_t tvec;
956
957 time(&tvec);
958 if (!SF && !tof)
959 (void)write(ofd, FF, strlen(FF));
960 if (SB) { /* short banner only */
961 if (class[0]) {
962 (void)write(ofd, class, strlen(class));
963 (void)write(ofd, ":", 1);
964 }
965 (void)write(ofd, name1, strlen(name1));
966 (void)write(ofd, " Job: ", 7);
967 (void)write(ofd, name2, strlen(name2));
968 (void)write(ofd, " Date: ", 8);
969 (void)write(ofd, ctime(&tvec), 24);
970 (void)write(ofd, "\n", 1);
971 } else { /* normal banner */
972 (void)write(ofd, "\n\n\n", 3);
973 scan_out(ofd, name1, '\0');
974 (void)write(ofd, "\n\n", 2);
975 scan_out(ofd, name2, '\0');
976 if (class[0]) {
977 (void)write(ofd,"\n\n\n",3);
978 scan_out(ofd, class, '\0');
979 }
980 (void)write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
981 (void)write(ofd, name2, strlen(name2));
982 (void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
983 (void)write(ofd, ctime(&tvec), 24);
984 (void)write(ofd, "\n", 1);
985 }
986 if (!SF)
987 (void)write(ofd, FF, strlen(FF));
988 tof = 1;
989 }
990
991 static char *
992 scnline(int key, char *p, int c)
993 {
994 int scnwidth;
995
996 for (scnwidth = WIDTH; --scnwidth;) {
997 key <<= 1;
998 *p++ = key & 0200 ? c : BACKGND;
999 }
1000 return (p);
1001 }
1002
1003 #define TRC(q) (((q)-' ')&0177)
1004
1005 static void
1006 scan_out(int scfd, char *scsp, int dlm)
1007 {
1008 char *strp;
1009 int nchrs, j;
1010 char outbuf[LINELEN+1], *sp, c, cc;
1011 int d, scnhgt;
1012 extern char scnkey[][HEIGHT]; /* in lpdchar.c */
1013
1014 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1015 strp = &outbuf[0];
1016 sp = scsp;
1017 for (nchrs = 0; ; ) {
1018 d = dropit(c = TRC(cc = *sp++));
1019 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1020 for (j = WIDTH; --j;)
1021 *strp++ = BACKGND;
1022 else
1023 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1024 strp, cc);
1025 if (*sp == dlm || *sp == '\0' ||
1026 nchrs++ >= PW/(WIDTH+1)-1)
1027 break;
1028 *strp++ = BACKGND;
1029 *strp++ = BACKGND;
1030 }
1031 while (*--strp == BACKGND && strp >= outbuf)
1032 ;
1033 strp++;
1034 *strp++ = '\n';
1035 (void)write(scfd, outbuf, strp-outbuf);
1036 }
1037 }
1038
1039 static int
1040 dropit(int c)
1041 {
1042 switch(c) {
1043
1044 case TRC('_'):
1045 case TRC(';'):
1046 case TRC(','):
1047 case TRC('g'):
1048 case TRC('j'):
1049 case TRC('p'):
1050 case TRC('q'):
1051 case TRC('y'):
1052 return (DROP);
1053
1054 default:
1055 return (0);
1056 }
1057 }
1058
1059 /*
1060 * sendmail ---
1061 * tell people about job completion
1062 */
1063 static void
1064 sendmail(char *user, int bombed)
1065 {
1066 int i, p[2], s, nofile;
1067 char *cp = NULL; /* XXX gcc */
1068 struct stat stb;
1069 FILE *fp;
1070
1071 if (user[0] == '-' || user[0] == '/' || !isprint(user[0]))
1072 return;
1073 pipe(p);
1074 if ((s = dofork(DORETURN)) == 0) { /* child */
1075 dup2(p[0], 0);
1076 closelog();
1077 nofile = sysconf(_SC_OPEN_MAX);
1078 for (i = 3; i < nofile; i++)
1079 (void)close(i);
1080 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1081 cp++;
1082 else
1083 cp = _PATH_SENDMAIL;
1084 execl(_PATH_SENDMAIL, cp, "-t", 0);
1085 _exit(0);
1086 } else if (s > 0) { /* parent */
1087 dup2(p[1], 1);
1088 printf("To: %s@%s\n", user, fromhost);
1089 printf("Subject: %s printer job \"%s\"\n", printer,
1090 *jobname ? jobname : "<unknown>");
1091 printf("Reply-To: root@%s\n\n", host);
1092 printf("Your printer job ");
1093 if (*jobname)
1094 printf("(%s) ", jobname);
1095 switch (bombed) {
1096 case OK:
1097 printf("\ncompleted successfully\n");
1098 cp = "OK";
1099 break;
1100 default:
1101 case FATALERR:
1102 printf("\ncould not be printed\n");
1103 cp = "FATALERR";
1104 break;
1105 case NOACCT:
1106 printf("\ncould not be printed without an account on %s\n", host);
1107 cp = "NOACCT";
1108 break;
1109 case FILTERERR:
1110 cp = "FILTERERR";
1111 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1112 (fp = fopen(tempfile, "r")) == NULL) {
1113 printf("\nhad some errors and may not have printed\n");
1114 break;
1115 }
1116 printf("\nhad the following errors and may not have printed:\n");
1117 while ((i = getc(fp)) != EOF)
1118 putchar(i);
1119 (void)fclose(fp);
1120 break;
1121 case ACCESS:
1122 printf("\nwas not printed because it was not linked to the original file\n");
1123 cp = "ACCESS";
1124 }
1125 fflush(stdout);
1126 (void)close(1);
1127 } else {
1128 syslog(LOG_ERR, "fork for sendmail failed: %m");
1129 }
1130 (void)close(p[0]);
1131 (void)close(p[1]);
1132 if (s > 0) {
1133 wait(NULL);
1134 syslog(LOG_INFO, "mail sent to user %s about job %s on "
1135 "printer %s (%s)", user, *jobname ? jobname : "<unknown>",
1136 printer, cp);
1137 }
1138 }
1139
1140 /*
1141 * dofork - fork with retries on failure
1142 */
1143 static int
1144 dofork(int action)
1145 {
1146 int i, pid;
1147 struct passwd *pw;
1148
1149 for (i = 0; i < 20; i++) {
1150 if ((pid = fork()) < 0) {
1151 sleep((unsigned)(i*i));
1152 continue;
1153 }
1154 /*
1155 * Child should run as daemon instead of root
1156 */
1157 if (pid == 0) {
1158 pw = getpwuid(DU);
1159 if (pw == 0) {
1160 syslog(LOG_ERR, "uid %ld not in password file",
1161 DU);
1162 break;
1163 }
1164 initgroups(pw->pw_name, pw->pw_gid);
1165 setgid(pw->pw_gid);
1166 setuid(DU);
1167 }
1168 return (pid);
1169 }
1170 syslog(LOG_ERR, "can't fork");
1171
1172 switch (action) {
1173 case DORETURN:
1174 return (-1);
1175 default:
1176 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1177 /*FALL THRU*/
1178 case DOABORT:
1179 exit(1);
1180 }
1181 /*NOTREACHED*/
1182 }
1183
1184 /*
1185 * Kill child processes to abort current job.
1186 */
1187 static void
1188 abortpr(int signo)
1189 {
1190 (void)unlink(tempfile);
1191 kill(0, SIGINT);
1192 if (ofilter > 0)
1193 kill(ofilter, SIGCONT);
1194 while (wait(NULL) > 0)
1195 ;
1196 exit(0);
1197 }
1198
1199 static void
1200 init(void)
1201 {
1202 int status;
1203 char *s;
1204
1205 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1206 syslog(LOG_ERR, "can't open printer description file");
1207 exit(1);
1208 } else if (status == -1) {
1209 syslog(LOG_ERR, "unknown printer: %s", printer);
1210 exit(1);
1211 } else if (status == -3)
1212 fatal("potential reference loop detected in printcap file");
1213
1214 if (cgetstr(bp, DEFLP, &LP) == -1)
1215 LP = _PATH_DEFDEVLP;
1216 if (cgetstr(bp, "rp", &RP) == -1)
1217 RP = DEFLP;
1218 if (cgetstr(bp, "lo", &LO) == -1)
1219 LO = DEFLOCK;
1220 if (cgetstr(bp, "st", &ST) == -1)
1221 ST = DEFSTAT;
1222 if (cgetstr(bp, "lf", &LF) == -1)
1223 LF = _PATH_CONSOLE;
1224 if (cgetstr(bp, "sd", &SD) == -1)
1225 SD = _PATH_DEFSPOOL;
1226 if (cgetnum(bp, "du", &DU) < 0)
1227 DU = DEFUID;
1228 if (cgetstr(bp,"ff", &FF) == -1)
1229 FF = DEFFF;
1230 if (cgetnum(bp, "pw", &PW) < 0)
1231 PW = DEFWIDTH;
1232 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1233 if (cgetnum(bp, "pl", &PL) < 0)
1234 PL = DEFLENGTH;
1235 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1236 if (cgetnum(bp,"px", &PX) < 0)
1237 PX = 0;
1238 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1239 if (cgetnum(bp, "py", &PY) < 0)
1240 PY = 0;
1241 (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
1242 cgetstr(bp, "rm", &RM);
1243 if ((s = checkremote()) != NULL)
1244 syslog(LOG_WARNING, "%s", s);
1245
1246 cgetstr(bp, "af", &AF);
1247 cgetstr(bp, "of", &OF);
1248 cgetstr(bp, "if", &IF);
1249 cgetstr(bp, "rf", &RF);
1250 cgetstr(bp, "tf", &TF);
1251 cgetstr(bp, "nf", &NF);
1252 cgetstr(bp, "df", &DF);
1253 cgetstr(bp, "gf", &GF);
1254 cgetstr(bp, "vf", &VF);
1255 cgetstr(bp, "cf", &CF);
1256 cgetstr(bp, "tr", &TR);
1257
1258 RS = (cgetcap(bp, "rs", ':') != NULL);
1259 SF = (cgetcap(bp, "sf", ':') != NULL);
1260 SH = (cgetcap(bp, "sh", ':') != NULL);
1261 SB = (cgetcap(bp, "sb", ':') != NULL);
1262 HL = (cgetcap(bp, "hl", ':') != NULL);
1263 RW = (cgetcap(bp, "rw", ':') != NULL);
1264
1265 cgetnum(bp, "br", &BR);
1266 if (cgetnum(bp, "fc", &FC) < 0)
1267 FC = 0;
1268 if (cgetnum(bp, "fs", &FS) < 0)
1269 FS = 0;
1270 if (cgetnum(bp, "xc", &XC) < 0)
1271 XC = 0;
1272 if (cgetnum(bp, "xs", &XS) < 0)
1273 XS = 0;
1274 cgetstr(bp, "ms", &MS);
1275
1276 tof = (cgetcap(bp, "fo", ':') == NULL);
1277 }
1278
1279 /*
1280 * Acquire line printer or remote connection.
1281 */
1282 static void
1283 openpr(void)
1284 {
1285 int i, nofile;
1286 char *cp;
1287 extern int rflag;
1288
1289 if (!remote && *LP) {
1290 if ((cp = strchr(LP, '@')))
1291 opennet(cp);
1292 else
1293 opentty();
1294 } else if (remote) {
1295 openrem();
1296 } else {
1297 syslog(LOG_ERR, "%s: no line printer device or host name",
1298 printer);
1299 exit(1);
1300 }
1301
1302 /*
1303 * Start up an output filter, if needed.
1304 */
1305 if ((!remote || rflag) && OF) {
1306 int p[2];
1307
1308 pipe(p);
1309 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1310 dup2(p[0], 0); /* pipe is std in */
1311 dup2(pfd, 1); /* printer is std out */
1312 closelog();
1313 nofile = sysconf(_SC_OPEN_MAX);
1314 for (i = 3; i < nofile; i++)
1315 (void)close(i);
1316 if ((cp = strrchr(OF, '/')) == NULL)
1317 cp = OF;
1318 else
1319 cp++;
1320 execl(OF, cp, width, length, 0);
1321 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1322 exit(1);
1323 }
1324 (void)close(p[0]); /* close input side */
1325 ofd = p[1]; /* use pipe for output */
1326 } else {
1327 ofd = pfd;
1328 ofilter = 0;
1329 }
1330 }
1331
1332 /*
1333 * Printer connected directly to the network
1334 * or to a terminal server on the net
1335 */
1336 static void
1337 opennet(char *cp)
1338 {
1339 int i;
1340 int resp, port;
1341 char save_ch;
1342
1343 save_ch = *cp;
1344 *cp = '\0';
1345 port = atoi(LP);
1346 if (port <= 0) {
1347 syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1348 exit(1);
1349 }
1350 *cp++ = save_ch;
1351
1352 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1353 resp = -1;
1354 pfd = getport(cp, port);
1355 if (pfd < 0 && errno == ECONNREFUSED)
1356 resp = 1;
1357 else if (pfd >= 0) {
1358 /*
1359 * need to delay a bit for rs232 lines
1360 * to stabilize in case printer is
1361 * connected via a terminal server
1362 */
1363 delay(500);
1364 break;
1365 }
1366 if (i == 1) {
1367 if (resp < 0)
1368 pstatus("waiting for %s to come up", LP);
1369 else
1370 pstatus("waiting for access to printer on %s", LP);
1371 }
1372 sleep(i);
1373 }
1374 pstatus("sending to %s port %d", cp, port);
1375 }
1376
1377 /*
1378 * Printer is connected to an RS232 port on this host
1379 */
1380 static void
1381 opentty(void)
1382 {
1383 int i;
1384
1385 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1386 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1387 if (pfd >= 0) {
1388 delay(500);
1389 break;
1390 }
1391 if (errno == ENOENT) {
1392 syslog(LOG_ERR, "%s: %m", LP);
1393 exit(1);
1394 }
1395 if (i == 1)
1396 pstatus("waiting for %s to become ready (offline ?)",
1397 printer);
1398 sleep(i);
1399 }
1400 if (isatty(pfd))
1401 setty();
1402 pstatus("%s is ready and printing", printer);
1403 }
1404
1405 /*
1406 * Printer is on a remote host
1407 */
1408 static void
1409 openrem(void)
1410 {
1411 int i, n;
1412 int resp;
1413
1414 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1415 resp = -1;
1416 pfd = getport(RM, 0);
1417 if (pfd >= 0) {
1418 n = snprintf(line, sizeof(line), "\2%s\n", RP);
1419 if (write(pfd, line, n) == n &&
1420 (resp = response()) == '\0')
1421 break;
1422 (void) close(pfd);
1423 }
1424 if (i == 1) {
1425 if (resp < 0)
1426 pstatus("waiting for %s to come up", RM);
1427 else {
1428 pstatus("waiting for queue to be enabled on %s",
1429 RM);
1430 i = 256;
1431 }
1432 }
1433 sleep(i);
1434 }
1435 pstatus("sending to %s", RM);
1436 }
1437
1438 static void
1439 alarmer(int s)
1440 {
1441 /* nothing */
1442 }
1443
1444 #if !defined(__NetBSD__)
1445 struct bauds {
1446 int baud;
1447 int speed;
1448 } bauds[] = {
1449 50, B50,
1450 75, B75,
1451 110, B110,
1452 134, B134,
1453 150, B150,
1454 200, B200,
1455 300, B300,
1456 600, B600,
1457 1200, B1200,
1458 1800, B1800,
1459 2400, B2400,
1460 4800, B4800,
1461 9600, B9600,
1462 19200, B19200,
1463 38400, B38400,
1464 57600, B57600,
1465 115200, B115200,
1466 0, 0
1467 };
1468 #endif
1469
1470 /*
1471 * setup tty lines.
1472 */
1473 static void
1474 setty(void)
1475 {
1476 struct info i;
1477 char **argv, **ap, *p, *val;
1478
1479 i.fd = pfd;
1480 i.set = i.wset = 0;
1481 if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
1482 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1483 exit(1);
1484 }
1485 if (tcgetattr(i.fd, &i.t) < 0) {
1486 syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1487 exit(1);
1488 }
1489 if (BR > 0) {
1490 #if !defined(__NetBSD__)
1491 struct bauds *bp;
1492 for (bp = bauds; bp->baud; bp++)
1493 if (BR == bp->baud)
1494 break;
1495 if (!bp->baud) {
1496 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1497 exit(1);
1498 }
1499 cfsetspeed(&i.t, bp->speed);
1500 #else
1501 cfsetspeed(&i.t, BR);
1502 #endif
1503 i.set = 1;
1504 }
1505 if (MS) {
1506 if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
1507 syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
1508 exit(1);
1509 }
1510 if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
1511 syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
1512 printer);
1513
1514 argv = (char **)calloc(256, sizeof(char *));
1515 if (argv == NULL) {
1516 syslog(LOG_ERR, "%s: calloc: %m", printer);
1517 exit(1);
1518 }
1519 p = strdup(MS);
1520 ap = argv;
1521 while ((val = strsep(&p, " \t,")) != NULL) {
1522 *ap++ = strdup(val);
1523 }
1524
1525 for (; *argv; ++argv) {
1526 if (ksearch(&argv, &i))
1527 continue;
1528 if (msearch(&argv, &i))
1529 continue;
1530 syslog(LOG_INFO, "%s: unknown stty flag: %s",
1531 printer, *argv);
1532 }
1533 } else {
1534 if (FC) {
1535 sttyclearflags(&i.t, FC);
1536 i.set = 1;
1537 }
1538 if (FS) {
1539 sttysetflags(&i.t, FS);
1540 i.set = 1;
1541 }
1542 if (XC) {
1543 sttyclearlflags(&i.t, XC);
1544 i.set = 1;
1545 }
1546 if (XS) {
1547 sttysetlflags(&i.t, XS);
1548 i.set = 1;
1549 }
1550 }
1551
1552 if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
1553 syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1554 exit(1);
1555 }
1556 if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
1557 syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
1558 return;
1559 }
1560
1561 #include <stdarg.h>
1562
1563 static void
1564 pstatus(const char *msg, ...)
1565 {
1566 int fd;
1567 char *buf;
1568 va_list ap;
1569
1570 umask(0);
1571 fd = open(ST, O_WRONLY|O_CREAT, 0664);
1572 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1573 syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1574 exit(1);
1575 }
1576 ftruncate(fd, 0);
1577 va_start(ap, msg);
1578 (void)vasprintf(&buf, msg, ap);
1579 va_end(ap);
1580 /* XXX writev */
1581 (void)write(fd, buf, strlen(buf));
1582 (void)write(fd, "\n", 2);
1583 (void)close(fd);
1584 free(buf);
1585 }
1586