printjob.c revision 1.32 1 /* $NetBSD: printjob.c,v 1.32 2002/06/08 23:40:12 itojun 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.32 2002/06/08 23:40:12 itojun 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(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(key, p, c)
993 int key;
994 char *p;
995 int c;
996 {
997 int scnwidth;
998
999 for (scnwidth = WIDTH; --scnwidth;) {
1000 key <<= 1;
1001 *p++ = key & 0200 ? c : BACKGND;
1002 }
1003 return (p);
1004 }
1005
1006 #define TRC(q) (((q)-' ')&0177)
1007
1008 static void
1009 scan_out(int scfd, char *scsp, int dlm)
1010 {
1011 char *strp;
1012 int nchrs, j;
1013 char outbuf[LINELEN+1], *sp, c, cc;
1014 int d, scnhgt;
1015 extern char scnkey[][HEIGHT]; /* in lpdchar.c */
1016
1017 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1018 strp = &outbuf[0];
1019 sp = scsp;
1020 for (nchrs = 0; ; ) {
1021 d = dropit(c = TRC(cc = *sp++));
1022 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1023 for (j = WIDTH; --j;)
1024 *strp++ = BACKGND;
1025 else
1026 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1027 strp, cc);
1028 if (*sp == dlm || *sp == '\0' ||
1029 nchrs++ >= PW/(WIDTH+1)-1)
1030 break;
1031 *strp++ = BACKGND;
1032 *strp++ = BACKGND;
1033 }
1034 while (*--strp == BACKGND && strp >= outbuf)
1035 ;
1036 strp++;
1037 *strp++ = '\n';
1038 (void)write(scfd, outbuf, strp-outbuf);
1039 }
1040 }
1041
1042 static int
1043 dropit(c)
1044 int c;
1045 {
1046 switch(c) {
1047
1048 case TRC('_'):
1049 case TRC(';'):
1050 case TRC(','):
1051 case TRC('g'):
1052 case TRC('j'):
1053 case TRC('p'):
1054 case TRC('q'):
1055 case TRC('y'):
1056 return (DROP);
1057
1058 default:
1059 return (0);
1060 }
1061 }
1062
1063 /*
1064 * sendmail ---
1065 * tell people about job completion
1066 */
1067 static void
1068 sendmail(char *user, int bombed)
1069 {
1070 int i, p[2], s, nofile;
1071 char *cp = NULL; /* XXX gcc */
1072 struct stat stb;
1073 FILE *fp;
1074
1075 if (user[0] == '-' || user[0] == '/' || !isprint(user[0]))
1076 return;
1077 pipe(p);
1078 if ((s = dofork(DORETURN)) == 0) { /* child */
1079 dup2(p[0], 0);
1080 closelog();
1081 nofile = sysconf(_SC_OPEN_MAX);
1082 for (i = 3; i < nofile; i++)
1083 (void)close(i);
1084 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1085 cp++;
1086 else
1087 cp = _PATH_SENDMAIL;
1088 execl(_PATH_SENDMAIL, cp, "-t", 0);
1089 _exit(0);
1090 } else if (s > 0) { /* parent */
1091 dup2(p[1], 1);
1092 printf("To: %s@%s\n", user, fromhost);
1093 printf("Subject: %s printer job \"%s\"\n", printer,
1094 *jobname ? jobname : "<unknown>");
1095 printf("Reply-To: root@%s\n\n", host);
1096 printf("Your printer job ");
1097 if (*jobname)
1098 printf("(%s) ", jobname);
1099 switch (bombed) {
1100 case OK:
1101 printf("\ncompleted successfully\n");
1102 cp = "OK";
1103 break;
1104 default:
1105 case FATALERR:
1106 printf("\ncould not be printed\n");
1107 cp = "FATALERR";
1108 break;
1109 case NOACCT:
1110 printf("\ncould not be printed without an account on %s\n", host);
1111 cp = "NOACCT";
1112 break;
1113 case FILTERERR:
1114 cp = "FILTERERR";
1115 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1116 (fp = fopen(tempfile, "r")) == NULL) {
1117 printf("\nhad some errors and may not have printed\n");
1118 break;
1119 }
1120 printf("\nhad the following errors and may not have printed:\n");
1121 while ((i = getc(fp)) != EOF)
1122 putchar(i);
1123 (void)fclose(fp);
1124 break;
1125 case ACCESS:
1126 printf("\nwas not printed because it was not linked to the original file\n");
1127 cp = "ACCESS";
1128 }
1129 fflush(stdout);
1130 (void)close(1);
1131 } else {
1132 syslog(LOG_ERR, "fork for sendmail failed: %m");
1133 }
1134 (void)close(p[0]);
1135 (void)close(p[1]);
1136 if (s > 0) {
1137 wait(NULL);
1138 syslog(LOG_INFO, "mail sent to user %s about job %s on "
1139 "printer %s (%s)", user, *jobname ? jobname : "<unknown>",
1140 printer, cp);
1141 }
1142 }
1143
1144 /*
1145 * dofork - fork with retries on failure
1146 */
1147 static int
1148 dofork(int action)
1149 {
1150 int i, pid;
1151 struct passwd *pw;
1152
1153 for (i = 0; i < 20; i++) {
1154 if ((pid = fork()) < 0) {
1155 sleep((unsigned)(i*i));
1156 continue;
1157 }
1158 /*
1159 * Child should run as daemon instead of root
1160 */
1161 if (pid == 0) {
1162 pw = getpwuid(DU);
1163 if (pw == 0) {
1164 syslog(LOG_ERR, "uid %ld not in password file",
1165 DU);
1166 break;
1167 }
1168 initgroups(pw->pw_name, pw->pw_gid);
1169 setgid(pw->pw_gid);
1170 setuid(DU);
1171 }
1172 return (pid);
1173 }
1174 syslog(LOG_ERR, "can't fork");
1175
1176 switch (action) {
1177 case DORETURN:
1178 return (-1);
1179 default:
1180 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1181 /*FALL THRU*/
1182 case DOABORT:
1183 exit(1);
1184 }
1185 /*NOTREACHED*/
1186 }
1187
1188 /*
1189 * Kill child processes to abort current job.
1190 */
1191 static void
1192 abortpr(signo)
1193 int signo;
1194 {
1195 (void)unlink(tempfile);
1196 kill(0, SIGINT);
1197 if (ofilter > 0)
1198 kill(ofilter, SIGCONT);
1199 while (wait(NULL) > 0)
1200 ;
1201 exit(0);
1202 }
1203
1204 static void
1205 init(void)
1206 {
1207 int status;
1208 char *s;
1209
1210 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1211 syslog(LOG_ERR, "can't open printer description file");
1212 exit(1);
1213 } else if (status == -1) {
1214 syslog(LOG_ERR, "unknown printer: %s", printer);
1215 exit(1);
1216 } else if (status == -3)
1217 fatal("potential reference loop detected in printcap file");
1218
1219 if (cgetstr(bp, DEFLP, &LP) == -1)
1220 LP = _PATH_DEFDEVLP;
1221 if (cgetstr(bp, "rp", &RP) == -1)
1222 RP = DEFLP;
1223 if (cgetstr(bp, "lo", &LO) == -1)
1224 LO = DEFLOCK;
1225 if (cgetstr(bp, "st", &ST) == -1)
1226 ST = DEFSTAT;
1227 if (cgetstr(bp, "lf", &LF) == -1)
1228 LF = _PATH_CONSOLE;
1229 if (cgetstr(bp, "sd", &SD) == -1)
1230 SD = _PATH_DEFSPOOL;
1231 if (cgetnum(bp, "du", &DU) < 0)
1232 DU = DEFUID;
1233 if (cgetstr(bp,"ff", &FF) == -1)
1234 FF = DEFFF;
1235 if (cgetnum(bp, "pw", &PW) < 0)
1236 PW = DEFWIDTH;
1237 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1238 if (cgetnum(bp, "pl", &PL) < 0)
1239 PL = DEFLENGTH;
1240 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1241 if (cgetnum(bp,"px", &PX) < 0)
1242 PX = 0;
1243 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1244 if (cgetnum(bp, "py", &PY) < 0)
1245 PY = 0;
1246 (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
1247 cgetstr(bp, "rm", &RM);
1248 if ((s = checkremote()) != NULL)
1249 syslog(LOG_WARNING, "%s", s);
1250
1251 cgetstr(bp, "af", &AF);
1252 cgetstr(bp, "of", &OF);
1253 cgetstr(bp, "if", &IF);
1254 cgetstr(bp, "rf", &RF);
1255 cgetstr(bp, "tf", &TF);
1256 cgetstr(bp, "nf", &NF);
1257 cgetstr(bp, "df", &DF);
1258 cgetstr(bp, "gf", &GF);
1259 cgetstr(bp, "vf", &VF);
1260 cgetstr(bp, "cf", &CF);
1261 cgetstr(bp, "tr", &TR);
1262
1263 RS = (cgetcap(bp, "rs", ':') != NULL);
1264 SF = (cgetcap(bp, "sf", ':') != NULL);
1265 SH = (cgetcap(bp, "sh", ':') != NULL);
1266 SB = (cgetcap(bp, "sb", ':') != NULL);
1267 HL = (cgetcap(bp, "hl", ':') != NULL);
1268 RW = (cgetcap(bp, "rw", ':') != NULL);
1269
1270 cgetnum(bp, "br", &BR);
1271 if (cgetnum(bp, "fc", &FC) < 0)
1272 FC = 0;
1273 if (cgetnum(bp, "fs", &FS) < 0)
1274 FS = 0;
1275 if (cgetnum(bp, "xc", &XC) < 0)
1276 XC = 0;
1277 if (cgetnum(bp, "xs", &XS) < 0)
1278 XS = 0;
1279 cgetstr(bp, "ms", &MS);
1280
1281 tof = (cgetcap(bp, "fo", ':') == NULL);
1282 }
1283
1284 /*
1285 * Acquire line printer or remote connection.
1286 */
1287 static void
1288 openpr(void)
1289 {
1290 int i, nofile;
1291 char *cp;
1292 extern int rflag;
1293
1294 if (!remote && *LP) {
1295 if ((cp = strchr(LP, '@')))
1296 opennet(cp);
1297 else
1298 opentty();
1299 } else if (remote) {
1300 openrem();
1301 } else {
1302 syslog(LOG_ERR, "%s: no line printer device or host name",
1303 printer);
1304 exit(1);
1305 }
1306
1307 /*
1308 * Start up an output filter, if needed.
1309 */
1310 if ((!remote || rflag) && OF) {
1311 int p[2];
1312
1313 pipe(p);
1314 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1315 dup2(p[0], 0); /* pipe is std in */
1316 dup2(pfd, 1); /* printer is std out */
1317 closelog();
1318 nofile = sysconf(_SC_OPEN_MAX);
1319 for (i = 3; i < nofile; i++)
1320 (void)close(i);
1321 if ((cp = strrchr(OF, '/')) == NULL)
1322 cp = OF;
1323 else
1324 cp++;
1325 execl(OF, cp, width, length, 0);
1326 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1327 exit(1);
1328 }
1329 (void)close(p[0]); /* close input side */
1330 ofd = p[1]; /* use pipe for output */
1331 } else {
1332 ofd = pfd;
1333 ofilter = 0;
1334 }
1335 }
1336
1337 /*
1338 * Printer connected directly to the network
1339 * or to a terminal server on the net
1340 */
1341 static void
1342 opennet(char *cp)
1343 {
1344 int i;
1345 int resp, port;
1346 char save_ch;
1347
1348 save_ch = *cp;
1349 *cp = '\0';
1350 port = atoi(LP);
1351 if (port <= 0) {
1352 syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1353 exit(1);
1354 }
1355 *cp++ = save_ch;
1356
1357 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1358 resp = -1;
1359 pfd = getport(cp, port);
1360 if (pfd < 0 && errno == ECONNREFUSED)
1361 resp = 1;
1362 else if (pfd >= 0) {
1363 /*
1364 * need to delay a bit for rs232 lines
1365 * to stabilize in case printer is
1366 * connected via a terminal server
1367 */
1368 delay(500);
1369 break;
1370 }
1371 if (i == 1) {
1372 if (resp < 0)
1373 pstatus("waiting for %s to come up", LP);
1374 else
1375 pstatus("waiting for access to printer on %s", LP);
1376 }
1377 sleep(i);
1378 }
1379 pstatus("sending to %s port %d", cp, port);
1380 }
1381
1382 /*
1383 * Printer is connected to an RS232 port on this host
1384 */
1385 static void
1386 opentty(void)
1387 {
1388 int i;
1389
1390 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1391 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1392 if (pfd >= 0) {
1393 delay(500);
1394 break;
1395 }
1396 if (errno == ENOENT) {
1397 syslog(LOG_ERR, "%s: %m", LP);
1398 exit(1);
1399 }
1400 if (i == 1)
1401 pstatus("waiting for %s to become ready (offline ?)",
1402 printer);
1403 sleep(i);
1404 }
1405 if (isatty(pfd))
1406 setty();
1407 pstatus("%s is ready and printing", printer);
1408 }
1409
1410 /*
1411 * Printer is on a remote host
1412 */
1413 static void
1414 openrem(void)
1415 {
1416 int i, n;
1417 int resp;
1418
1419 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1420 resp = -1;
1421 pfd = getport(RM, 0);
1422 if (pfd >= 0) {
1423 n = snprintf(line, sizeof(line), "\2%s\n", RP);
1424 if (write(pfd, line, n) == n &&
1425 (resp = response()) == '\0')
1426 break;
1427 (void) close(pfd);
1428 }
1429 if (i == 1) {
1430 if (resp < 0)
1431 pstatus("waiting for %s to come up", RM);
1432 else {
1433 pstatus("waiting for queue to be enabled on %s",
1434 RM);
1435 i = 256;
1436 }
1437 }
1438 sleep(i);
1439 }
1440 pstatus("sending to %s", RM);
1441 }
1442
1443 static void
1444 alarmer(int s)
1445 {
1446 /* nothing */
1447 }
1448
1449 #if !defined(__NetBSD__)
1450 struct bauds {
1451 int baud;
1452 int speed;
1453 } bauds[] = {
1454 50, B50,
1455 75, B75,
1456 110, B110,
1457 134, B134,
1458 150, B150,
1459 200, B200,
1460 300, B300,
1461 600, B600,
1462 1200, B1200,
1463 1800, B1800,
1464 2400, B2400,
1465 4800, B4800,
1466 9600, B9600,
1467 19200, B19200,
1468 38400, B38400,
1469 57600, B57600,
1470 115200, B115200,
1471 0, 0
1472 };
1473 #endif
1474
1475 /*
1476 * setup tty lines.
1477 */
1478 static void
1479 setty(void)
1480 {
1481 struct info i;
1482 char **argv, **ap, *p, *val;
1483
1484 i.fd = pfd;
1485 i.set = i.wset = 0;
1486 if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
1487 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1488 exit(1);
1489 }
1490 if (tcgetattr(i.fd, &i.t) < 0) {
1491 syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1492 exit(1);
1493 }
1494 if (BR > 0) {
1495 #if !defined(__NetBSD__)
1496 struct bauds *bp;
1497 for (bp = bauds; bp->baud; bp++)
1498 if (BR == bp->baud)
1499 break;
1500 if (!bp->baud) {
1501 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1502 exit(1);
1503 }
1504 cfsetspeed(&i.t, bp->speed);
1505 #else
1506 cfsetspeed(&i.t, BR);
1507 #endif
1508 i.set = 1;
1509 }
1510 if (MS) {
1511 if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
1512 syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
1513 exit(1);
1514 }
1515 if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
1516 syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
1517 printer);
1518
1519 argv = (char **)calloc(256, sizeof(char *));
1520 if (argv == NULL) {
1521 syslog(LOG_ERR, "%s: calloc: %m", printer);
1522 exit(1);
1523 }
1524 p = strdup(MS);
1525 ap = argv;
1526 while ((val = strsep(&p, " \t,")) != NULL) {
1527 *ap++ = strdup(val);
1528 }
1529
1530 for (; *argv; ++argv) {
1531 if (ksearch(&argv, &i))
1532 continue;
1533 if (msearch(&argv, &i))
1534 continue;
1535 syslog(LOG_INFO, "%s: unknown stty flag: %s",
1536 printer, *argv);
1537 }
1538 } else {
1539 if (FC) {
1540 sttyclearflags(&i.t, FC);
1541 i.set = 1;
1542 }
1543 if (FS) {
1544 sttysetflags(&i.t, FS);
1545 i.set = 1;
1546 }
1547 if (XC) {
1548 sttyclearlflags(&i.t, XC);
1549 i.set = 1;
1550 }
1551 if (XS) {
1552 sttysetlflags(&i.t, XS);
1553 i.set = 1;
1554 }
1555 }
1556
1557 if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
1558 syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1559 exit(1);
1560 }
1561 if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
1562 syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
1563 return;
1564 }
1565
1566 #ifdef __STDC__
1567 #include <stdarg.h>
1568 #else
1569 #include <varargs.h>
1570 #endif
1571
1572 static void
1573 #ifdef __STDC__
1574 pstatus(const char *msg, ...)
1575 #else
1576 pstatus(msg, va_alist)
1577 char *msg;
1578 va_dcl
1579 #endif
1580 {
1581 int fd;
1582 char *buf;
1583 va_list ap;
1584
1585 umask(0);
1586 fd = open(ST, O_WRONLY|O_CREAT, 0664);
1587 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1588 syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1589 exit(1);
1590 }
1591 ftruncate(fd, 0);
1592 #ifdef __STDC__
1593 va_start(ap, msg);
1594 #else
1595 va_start(ap);
1596 #endif
1597 (void)vasprintf(&buf, msg, ap);
1598 va_end(ap);
1599 /* XXX writev */
1600 (void)write(fd, buf, strlen(buf));
1601 (void)write(fd, "\n", 2);
1602 (void)close(fd);
1603 free(buf);
1604 }
1605