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