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