printjob.c revision 1.45 1 /* $NetBSD: printjob.c,v 1.45 2006/01/17 19:11:13 garbled 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.45 2006/01/17 19:11:13 garbled 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(char *);
129 static void opentty(void);
130 static void openrem(void);
131 static int print(int, char *);
132 static int printit(char *);
133 static void pstatus(const char *, ...)
134 __attribute__((__format__(__printf__, 1, 2)));
135 static char response(void);
136 static void scan_out(int, char *, int);
137 static char *scnline(int, char *, int);
138 static int sendfile(int, char *);
139 static int sendit(char *);
140 static void sendmail(char *, int);
141 static void setty(void);
142 static void alarmer(int);
143
144 void
145 printjob(void)
146 {
147 struct stat stb;
148 struct queue *q, **qp;
149 struct queue **queue;
150 int i, nitems, 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 * 1 -- "R font file" for troff
373 * 2 -- "I font file" for troff
374 * 3 -- "B font file" for troff
375 * 4 -- "S font file" for troff
376 * N -- "name" of file (used by lpq)
377 * U -- "unlink" name of file to remove
378 * (after we print it. (Pass 2 only)).
379 * M -- "mail" to user when done printing
380 *
381 * getline reads a line and expands tabs to blanks
382 */
383
384 /* pass 1 */
385
386 while (getline(cfp))
387 switch (line[0]) {
388 case 'H':
389 strlcpy(fromhost, line+1, sizeof(fromhost));
390 if (class[0] == '\0')
391 strlcpy(class, line+1, sizeof(class));
392 continue;
393
394 case 'P':
395 strlcpy(logname, line+1, sizeof(logname));
396 if (RS) { /* restricted */
397 if (getpwnam(logname) == NULL) {
398 bombed = NOACCT;
399 sendmail(line+1, bombed);
400 goto pass2;
401 }
402 }
403 continue;
404
405 case 'S':
406 cp = line+1;
407 i = 0;
408 while (*cp >= '0' && *cp <= '9')
409 i = i * 10 + (*cp++ - '0');
410 fdev = i;
411 cp++;
412 i = 0;
413 while (*cp >= '0' && *cp <= '9')
414 i = i * 10 + (*cp++ - '0');
415 fino = i;
416 continue;
417
418 case 'J':
419 if (line[1] != '\0')
420 strlcpy(jobname, line+1, sizeof(jobname));
421 else {
422 jobname[0] = ' ';
423 jobname[1] = '\0';
424 }
425 continue;
426
427 case 'C':
428 if (line[1] != '\0')
429 strlcpy(class, line+1, sizeof(class));
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 strlcpy(title, line+1, sizeof(title));
438 continue;
439
440 case 'L': /* identification line */
441 if (!SH && !HL)
442 banner(line+1, jobname);
443 continue;
444
445 case '1': /* troff fonts */
446 case '2':
447 case '3':
448 case '4':
449 if (line[1] != '\0') {
450 strlcpy(fonts[line[0]-'1'], line+1,
451 sizeof(fonts[line[0]-'1']));
452 }
453 continue;
454
455 case 'W': /* page width */
456 strlcpy(width+2, line+1, sizeof(width) - 2);
457 continue;
458
459 case 'I': /* indent amount */
460 strlcpy(indent+2, line+1, sizeof(indent) - 2);
461 continue;
462
463 default: /* some file to print */
464 switch (i = print(line[0], line+1)) {
465 case ERROR:
466 if (bombed == OK)
467 bombed = FATALERR;
468 break;
469 case REPRINT:
470 (void)fclose(cfp);
471 return(REPRINT);
472 case FILTERERR:
473 case ACCESS:
474 bombed = i;
475 sendmail(logname, bombed);
476 }
477 title[0] = '\0';
478 continue;
479
480 case 'N':
481 case 'U':
482 case 'M':
483 case 'R':
484 continue;
485 }
486
487 /* pass 2 */
488
489 pass2:
490 fseek(cfp, 0L, 0);
491 while (getline(cfp))
492 switch (line[0]) {
493 case 'L': /* identification line */
494 if (!SH && HL)
495 banner(line+1, jobname);
496 continue;
497
498 case 'M':
499 if (bombed < NOACCT) /* already sent if >= NOACCT */
500 sendmail(line+1, bombed);
501 continue;
502
503 case 'U':
504 if (strchr(line+1, '/'))
505 continue;
506 (void)unlink(line+1);
507 }
508 /*
509 * clean-up in case another control file exists
510 */
511 (void)fclose(cfp);
512 (void)unlink(file);
513 return(bombed == OK ? OK : ERROR);
514 }
515
516 /*
517 * Print a file.
518 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
519 * Return -1 if a non-recoverable error occurred,
520 * 2 if the filter detected some errors (but printed the job anyway),
521 * 1 if we should try to reprint this job and
522 * 0 if all is well.
523 * Note: all filters take stdin as the file, stdout as the printer,
524 * stderr as the log file, and must not ignore SIGINT.
525 */
526 static int
527 print(int format, char *file)
528 {
529 FILE *fp;
530 int status;
531 struct stat stb;
532 const char *prog, *av[15];
533 char buf[BUFSIZ];
534 int n, fi, fo, child_pid, p[2], stopped = 0, nofile;
535
536 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
537 return(ERROR);
538 /*
539 * Check to see if data file is a symbolic link. If so, it should
540 * still point to the same file or someone is trying to print
541 * something he shouldn't.
542 */
543 if (S_ISLNK(stb.st_mode) && fstat(fi, &stb) == 0 &&
544 (stb.st_dev != fdev || stb.st_ino != fino))
545 return(ACCESS);
546 if (!SF && !tof) { /* start on a fresh page */
547 (void)write(ofd, FF, strlen(FF));
548 tof = 1;
549 }
550 if (IF == NULL && (format == 'f' || format == 'l')) {
551 tof = 0;
552 while ((n = read(fi, buf, BUFSIZ)) > 0)
553 if (write(ofd, buf, n) != n) {
554 (void)close(fi);
555 return(REPRINT);
556 }
557 (void)close(fi);
558 return(OK);
559 }
560 switch (format) {
561 case 'p': /* print file using 'pr' */
562 if (IF == NULL) { /* use output filter */
563 prog = _PATH_PR;
564 av[0] = "pr";
565 av[1] = width;
566 av[2] = length;
567 av[3] = "-h";
568 av[4] = *title ? title : " ";
569 av[5] = 0;
570 fo = ofd;
571 goto start;
572 }
573 pipe(p);
574 if ((prchild = dofork(DORETURN)) == 0) { /* child */
575 dup2(fi, 0); /* file is stdin */
576 dup2(p[1], 1); /* pipe is stdout */
577 closelog();
578 nofile = sysconf(_SC_OPEN_MAX);
579 for (n = 3; n < nofile; n++)
580 (void)close(n);
581 execl(_PATH_PR, "pr", width, length,
582 "-h", *title ? title : " ", 0);
583 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
584 exit(2);
585 }
586 (void)close(p[1]); /* close output side */
587 (void)close(fi);
588 if (prchild < 0) {
589 prchild = 0;
590 (void)close(p[0]);
591 return(ERROR);
592 }
593 fi = p[0]; /* use pipe for input */
594 case 'f': /* print plain text file */
595 prog = IF;
596 av[1] = width;
597 av[2] = length;
598 av[3] = indent;
599 n = 4;
600 break;
601 case 'o': /* print a postscript file */
602 if (PF == NULL) {
603 /* if PF is not set, handle it like an 'l' */
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 } else {
612 prog = PF;
613 av[1] = pxwidth;
614 av[2] = pxlength;
615 n = 3;
616 break;
617 }
618 case 'l': /* like 'f' but pass control characters */
619 prog = IF;
620 av[1] = "-c";
621 av[2] = width;
622 av[3] = length;
623 av[4] = indent;
624 n = 5;
625 break;
626 case 'r': /* print a fortran text file */
627 prog = RF;
628 av[1] = width;
629 av[2] = length;
630 n = 3;
631 break;
632 case 't': /* print troff output */
633 case 'n': /* print ditroff output */
634 case 'd': /* print tex output */
635 (void)unlink(".railmag");
636 if ((fo = creat(".railmag", FILMOD)) < 0) {
637 syslog(LOG_ERR, "%s: cannot create .railmag", printer);
638 (void)unlink(".railmag");
639 } else {
640 for (n = 0; n < 4; n++) {
641 if (fonts[n][0] != '/')
642 (void)write(fo, _PATH_VFONT,
643 sizeof(_PATH_VFONT) - 1);
644 (void)write(fo, fonts[n], strlen(fonts[n]));
645 (void)write(fo, "\n", 1);
646 }
647 (void)close(fo);
648 }
649 prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
650 av[1] = pxwidth;
651 av[2] = pxlength;
652 n = 3;
653 break;
654 case 'c': /* print cifplot output */
655 prog = CF;
656 av[1] = pxwidth;
657 av[2] = pxlength;
658 n = 3;
659 break;
660 case 'g': /* print plot(1G) output */
661 prog = GF;
662 av[1] = pxwidth;
663 av[2] = pxlength;
664 n = 3;
665 break;
666 case 'v': /* print raster output */
667 prog = VF;
668 av[1] = pxwidth;
669 av[2] = pxlength;
670 n = 3;
671 break;
672 default:
673 (void)close(fi);
674 syslog(LOG_ERR, "%s: illegal format character '%c'",
675 printer, format);
676 return(ERROR);
677 }
678 if (prog == NULL) {
679 (void)close(fi);
680 syslog(LOG_ERR,
681 "%s: no filter found in printcap for format character '%c'",
682 printer, format);
683 return (ERROR);
684 }
685 if ((av[0] = strrchr(prog, '/')) != NULL)
686 av[0]++;
687 else
688 av[0] = prog;
689 av[n++] = "-n";
690 av[n++] = logname;
691 av[n++] = "-h";
692 av[n++] = fromhost;
693 av[n++] = AF;
694 av[n] = 0;
695 fo = pfd;
696 if (ofilter > 0) { /* stop output filter */
697 write(ofd, "\031\1", 2);
698 while ((child_pid =
699 wait3(&status, WUNTRACED, 0)) > 0 && child_pid != ofilter)
700 ;
701 if (WIFSTOPPED(status) == 0) {
702 (void)close(fi);
703 syslog(LOG_WARNING,
704 "%s: output filter died (retcode=%d termsig=%d)",
705 printer, WEXITSTATUS(status), WTERMSIG(status));
706 return(REPRINT);
707 }
708 stopped++;
709 }
710 start:
711 if ((child = dofork(DORETURN)) == 0) { /* child */
712 dup2(fi, 0);
713 dup2(fo, 1);
714 unlink(tempfile);
715 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
716 if (n >= 0)
717 dup2(n, 2);
718 closelog();
719 nofile = sysconf(_SC_OPEN_MAX);
720 for (n = 3; n < nofile; n++)
721 (void)close(n);
722 execv(prog, __UNCONST(av));
723 syslog(LOG_ERR, "cannot execv %s", prog);
724 exit(2);
725 }
726 if (child < 0) {
727 child = 0;
728 prchild = 0;
729 tof = 0;
730 syslog(LOG_ERR, "cannot start child process: %m");
731 return (ERROR);
732 }
733 (void)close(fi);
734 while ((child_pid = wait(&status)) > 0 && child_pid != child)
735 ;
736 child = 0;
737 prchild = 0;
738 if (stopped) { /* restart output filter */
739 if (kill(ofilter, SIGCONT) < 0) {
740 syslog(LOG_ERR, "cannot restart output filter");
741 exit(1);
742 }
743 }
744 tof = 0;
745
746 /* Copy filter output to "lf" logfile */
747 if ((fp = fopen(tempfile, "r")) != NULL) {
748 while (fgets(buf, sizeof(buf), fp))
749 fputs(buf, stderr);
750 fclose(fp);
751 }
752
753 if (!WIFEXITED(status)) {
754 syslog(LOG_WARNING,
755 "%s: Daemon filter '%c' terminated (pid=%d) (termsig=%d)",
756 printer, format, (int)child_pid, WTERMSIG(status));
757 return(ERROR);
758 }
759 switch (WEXITSTATUS(status)) {
760 case 0:
761 tof = 1;
762 return(OK);
763 case 1:
764 return(REPRINT);
765 case 2:
766 return(ERROR);
767 default:
768 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
769 printer, format, WEXITSTATUS(status));
770 return(FILTERERR);
771 }
772 }
773
774 /*
775 * Send the daemon control file (cf) and any data files.
776 * Return -1 if a non-recoverable error occurred, 1 if a recoverable error and
777 * 0 if all is well.
778 */
779 static int
780 sendit(char *file)
781 {
782 int i, err = OK;
783 char *cp, last[BUFSIZ];
784
785 /*
786 * open control file
787 */
788 if ((cfp = fopen(file, "r")) == NULL)
789 return(OK);
790 /*
791 * read the control file for work to do
792 *
793 * file format -- first character in the line is a command
794 * rest of the line is the argument.
795 * commands of interest are:
796 *
797 * a-z -- "file name" name of file to print
798 * U -- "unlink" name of file to remove
799 * (after we print it. (Pass 2 only)).
800 */
801
802 /*
803 * pass 1
804 */
805 while (getline(cfp)) {
806 again:
807 if (line[0] == 'S') {
808 cp = line+1;
809 i = 0;
810 while (*cp >= '0' && *cp <= '9')
811 i = i * 10 + (*cp++ - '0');
812 fdev = i;
813 cp++;
814 i = 0;
815 while (*cp >= '0' && *cp <= '9')
816 i = i * 10 + (*cp++ - '0');
817 fino = i;
818 continue;
819 }
820 if (line[0] >= 'a' && line[0] <= 'z') {
821 strlcpy(last, line, sizeof(last));
822 while ((i = getline(cfp)) != 0)
823 if (strcmp(last, line))
824 break;
825 switch (sendfile('\3', last+1)) {
826 case OK:
827 if (i)
828 goto again;
829 break;
830 case REPRINT:
831 (void)fclose(cfp);
832 return(REPRINT);
833 case ACCESS:
834 sendmail(logname, ACCESS);
835 case ERROR:
836 err = ERROR;
837 }
838 break;
839 }
840 }
841 if (err == OK && sendfile('\2', file) > 0) {
842 (void)fclose(cfp);
843 return(REPRINT);
844 }
845 /*
846 * pass 2
847 */
848 fseek(cfp, 0L, 0);
849 while (getline(cfp))
850 if (line[0] == 'U' && strchr(line+1, '/') == 0)
851 (void)unlink(line+1);
852 /*
853 * clean-up in case another control file exists
854 */
855 (void)fclose(cfp);
856 (void)unlink(file);
857 return(err);
858 }
859
860 /*
861 * Send a data file to the remote machine and spool it.
862 * Return positive if we should try resending.
863 */
864 static int
865 sendfile(int type, char *file)
866 {
867 int f, i, amt;
868 struct stat stb;
869 char buf[BUFSIZ];
870 int sizerr, resp;
871 extern int rflag;
872
873 if (type == '\3' && rflag && (OF || IF)) {
874 int save_pfd = pfd;
875
876 (void)unlink(tempremote);
877 pfd = open(tempremote, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
878 if (pfd == -1) {
879 pfd = save_pfd;
880 return ERROR;
881 }
882 setup_ofilter(1);
883 switch (i = print('f', file)) {
884 case ERROR:
885 case REPRINT:
886 case FILTERERR:
887 case ACCESS:
888 return(i);
889 }
890 close_ofilter();
891 pfd = save_pfd;
892 file = tempremote;
893 }
894
895 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
896 return(ERROR);
897 /*
898 * Check to see if data file is a symbolic link. If so, it should
899 * still point to the same file or someone is trying to print something
900 * he shouldn't.
901 */
902 if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
903 (stb.st_dev != fdev || stb.st_ino != fino))
904 return(ACCESS);
905
906 amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
907 (long long)stb.st_size, file);
908 for (i = 0; ; i++) {
909 if (write(pfd, buf, amt) != amt ||
910 (resp = response()) < 0 || resp == '\1') {
911 (void)close(f);
912 return(REPRINT);
913 } else if (resp == '\0')
914 break;
915 if (i == 0)
916 pstatus("no space on remote; waiting for queue to drain");
917 if (i == 10)
918 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
919 printer, RM);
920 sleep(5 * 60);
921 }
922 if (i)
923 pstatus("sending to %s", RM);
924 sizerr = 0;
925 for (i = 0; i < stb.st_size; i += BUFSIZ) {
926 struct sigaction osa, nsa;
927
928 amt = BUFSIZ;
929 if (i + amt > stb.st_size)
930 amt = stb.st_size - i;
931 if (sizerr == 0 && read(f, buf, amt) != amt)
932 sizerr = 1;
933 nsa.sa_handler = alarmer;
934 sigemptyset(&nsa.sa_mask);
935 sigaddset(&nsa.sa_mask, SIGALRM);
936 nsa.sa_flags = 0;
937 (void)sigaction(SIGALRM, &nsa, &osa);
938 alarm(wait_time);
939 if (write(pfd, buf, amt) != amt) {
940 alarm(0);
941 (void)sigaction(SIGALRM, &osa, NULL);
942 (void)close(f);
943 return(REPRINT);
944 }
945 alarm(0);
946 (void)sigaction(SIGALRM, &osa, NULL);
947 }
948
949 (void)close(f);
950 if (sizerr) {
951 syslog(LOG_INFO, "%s: %s: changed size", printer, file);
952 /* tell recvjob to ignore this file */
953 (void)write(pfd, "\1", 1);
954 return(ERROR);
955 }
956 if (write(pfd, "", 1) != 1 || response())
957 return(REPRINT);
958 return(OK);
959 }
960
961 /*
962 * Check to make sure there have been no errors and that both programs
963 * are in sync with eachother.
964 * Return non-zero if the connection was lost.
965 */
966 static char
967 response(void)
968 {
969 struct sigaction osa, nsa;
970 char resp;
971
972 nsa.sa_handler = alarmer;
973 sigemptyset(&nsa.sa_mask);
974 sigaddset(&nsa.sa_mask, SIGALRM);
975 nsa.sa_flags = 0;
976 (void)sigaction(SIGALRM, &nsa, &osa);
977 alarm(wait_time);
978 if (read(pfd, &resp, 1) != 1) {
979 syslog(LOG_INFO, "%s: lost connection", printer);
980 resp = -1;
981 }
982 alarm(0);
983 (void)sigaction(SIGALRM, &osa, NULL);
984 return (resp);
985 }
986
987 /*
988 * Banner printing stuff
989 */
990 static void
991 banner(char *name1, char *name2)
992 {
993 time_t tvec;
994
995 time(&tvec);
996 if (!SF && !tof)
997 (void)write(ofd, FF, strlen(FF));
998 if (SB) { /* short banner only */
999 if (class[0]) {
1000 (void)write(ofd, class, strlen(class));
1001 (void)write(ofd, ":", 1);
1002 }
1003 (void)write(ofd, name1, strlen(name1));
1004 (void)write(ofd, " Job: ", 7);
1005 (void)write(ofd, name2, strlen(name2));
1006 (void)write(ofd, " Date: ", 8);
1007 (void)write(ofd, ctime(&tvec), 24);
1008 (void)write(ofd, "\n", 1);
1009 } else { /* normal banner */
1010 (void)write(ofd, "\n\n\n", 3);
1011 scan_out(ofd, name1, '\0');
1012 (void)write(ofd, "\n\n", 2);
1013 scan_out(ofd, name2, '\0');
1014 if (class[0]) {
1015 (void)write(ofd,"\n\n\n",3);
1016 scan_out(ofd, class, '\0');
1017 }
1018 (void)write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1019 (void)write(ofd, name2, strlen(name2));
1020 (void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
1021 (void)write(ofd, ctime(&tvec), 24);
1022 (void)write(ofd, "\n", 1);
1023 }
1024 if (!SF)
1025 (void)write(ofd, FF, strlen(FF));
1026 tof = 1;
1027 }
1028
1029 static char *
1030 scnline(int key, char *p, int c)
1031 {
1032 int scnwidth;
1033
1034 for (scnwidth = WIDTH; --scnwidth;) {
1035 key <<= 1;
1036 *p++ = key & 0200 ? c : BACKGND;
1037 }
1038 return (p);
1039 }
1040
1041 #define TRC(q) (((q)-' ')&0177)
1042
1043 static void
1044 scan_out(int scfd, char *scsp, int dlm)
1045 {
1046 char *strp;
1047 int nchrs, j;
1048 char outbuf[LINELEN+1], *sp, c, cc;
1049 int d, scnhgt;
1050 extern char scnkey[][HEIGHT]; /* in lpdchar.c */
1051
1052 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1053 strp = &outbuf[0];
1054 sp = scsp;
1055 for (nchrs = 0; ; ) {
1056 d = dropit(c = TRC(cc = *sp++));
1057 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1058 for (j = WIDTH; --j;)
1059 *strp++ = BACKGND;
1060 else
1061 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1062 strp, cc);
1063 if (*sp == dlm || *sp == '\0' ||
1064 nchrs++ >= PW/(WIDTH+1)-1)
1065 break;
1066 *strp++ = BACKGND;
1067 *strp++ = BACKGND;
1068 }
1069 while (*--strp == BACKGND && strp >= outbuf)
1070 ;
1071 strp++;
1072 *strp++ = '\n';
1073 (void)write(scfd, outbuf, strp-outbuf);
1074 }
1075 }
1076
1077 static int
1078 dropit(int c)
1079 {
1080 switch(c) {
1081
1082 case TRC('_'):
1083 case TRC(';'):
1084 case TRC(','):
1085 case TRC('g'):
1086 case TRC('j'):
1087 case TRC('p'):
1088 case TRC('q'):
1089 case TRC('y'):
1090 return (DROP);
1091
1092 default:
1093 return (0);
1094 }
1095 }
1096
1097 /*
1098 * sendmail ---
1099 * tell people about job completion
1100 */
1101 static void
1102 sendmail(char *user, int bombed)
1103 {
1104 int i, p[2], s, nofile;
1105 const char *cp = NULL; /* XXX gcc */
1106 struct stat stb;
1107 FILE *fp;
1108
1109 if (user[0] == '-' || user[0] == '/' || !isprint((unsigned char)user[0]))
1110 return;
1111 pipe(p);
1112 if ((s = dofork(DORETURN)) == 0) { /* child */
1113 dup2(p[0], 0);
1114 closelog();
1115 nofile = sysconf(_SC_OPEN_MAX);
1116 for (i = 3; i < nofile; i++)
1117 (void)close(i);
1118 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1119 cp++;
1120 else
1121 cp = _PATH_SENDMAIL;
1122 execl(_PATH_SENDMAIL, cp, "-t", 0);
1123 _exit(0);
1124 } else if (s > 0) { /* parent */
1125 dup2(p[1], 1);
1126 printf("To: %s@%s\n", user, fromhost);
1127 printf("Subject: %s printer job \"%s\"\n", printer,
1128 *jobname ? jobname : "<unknown>");
1129 printf("Reply-To: root@%s\n\n", host);
1130 printf("Your printer job ");
1131 if (*jobname)
1132 printf("(%s) ", jobname);
1133 switch (bombed) {
1134 case OK:
1135 printf("\ncompleted successfully\n");
1136 cp = "OK";
1137 break;
1138 default:
1139 case FATALERR:
1140 printf("\ncould not be printed\n");
1141 cp = "FATALERR";
1142 break;
1143 case NOACCT:
1144 printf("\ncould not be printed without an account on %s\n", host);
1145 cp = "NOACCT";
1146 break;
1147 case FILTERERR:
1148 cp = "FILTERERR";
1149 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1150 (fp = fopen(tempfile, "r")) == NULL) {
1151 printf("\nhad some errors and may not have printed\n");
1152 break;
1153 }
1154 printf("\nhad the following errors and may not have printed:\n");
1155 while ((i = getc(fp)) != EOF)
1156 putchar(i);
1157 (void)fclose(fp);
1158 break;
1159 case ACCESS:
1160 printf("\nwas not printed because it was not linked to the original file\n");
1161 cp = "ACCESS";
1162 }
1163 fflush(stdout);
1164 (void)close(1);
1165 } else {
1166 syslog(LOG_ERR, "fork for sendmail failed: %m");
1167 }
1168 (void)close(p[0]);
1169 (void)close(p[1]);
1170 if (s > 0) {
1171 wait(NULL);
1172 syslog(LOG_INFO, "mail sent to user %s about job %s on "
1173 "printer %s (%s)", user, *jobname ? jobname : "<unknown>",
1174 printer, cp);
1175 }
1176 }
1177
1178 /*
1179 * dofork - fork with retries on failure
1180 */
1181 static int
1182 dofork(int action)
1183 {
1184 int i, child_pid;
1185 struct passwd *pw;
1186
1187 for (i = 0; i < 20; i++) {
1188 if ((child_pid = fork()) < 0) {
1189 sleep((unsigned)(i*i));
1190 continue;
1191 }
1192 /*
1193 * Child should run as daemon instead of root
1194 */
1195 if (child_pid == 0) {
1196 pw = getpwuid(DU);
1197 if (pw == 0) {
1198 syslog(LOG_ERR, "uid %ld not in password file",
1199 DU);
1200 break;
1201 }
1202 initgroups(pw->pw_name, pw->pw_gid);
1203 setgid(pw->pw_gid);
1204 setuid(DU);
1205 signal(SIGCHLD, SIG_DFL);
1206 }
1207 return (child_pid);
1208 }
1209 syslog(LOG_ERR, "can't fork");
1210
1211 switch (action) {
1212 case DORETURN:
1213 return (-1);
1214 default:
1215 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1216 /*FALL THRU*/
1217 case DOABORT:
1218 exit(1);
1219 }
1220 /*NOTREACHED*/
1221 }
1222
1223 /*
1224 * Kill child processes to abort current job.
1225 */
1226 static void
1227 abortpr(int signo)
1228 {
1229 (void)unlink(tempfile);
1230 (void)unlink(tempremote);
1231 kill(0, SIGINT);
1232 if (ofilter > 0)
1233 kill(ofilter, SIGCONT);
1234 while (wait(NULL) > 0)
1235 ;
1236 exit(0);
1237 }
1238
1239 static void
1240 init(void)
1241 {
1242 char *s;
1243
1244 getprintcap(printer);
1245
1246 FF = cgetstr(bp, "ff", &s) == -1 ? DEFFF : s;
1247
1248 if (cgetnum(bp, "du", &DU) < 0)
1249 DU = DEFUID;
1250 if (cgetnum(bp, "pw", &PW) < 0)
1251 PW = DEFWIDTH;
1252 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1253 if (cgetnum(bp, "pl", &PL) < 0)
1254 PL = DEFLENGTH;
1255 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1256 if (cgetnum(bp,"px", &PX) < 0)
1257 PX = 0;
1258 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1259 if (cgetnum(bp, "py", &PY) < 0)
1260 PY = 0;
1261 (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
1262
1263 AF = cgetstr(bp, "af", &s) == -1 ? NULL : s;
1264 OF = cgetstr(bp, "of", &s) == -1 ? NULL : s;
1265 IF = cgetstr(bp, "if", &s) == -1 ? NULL : s;
1266 RF = cgetstr(bp, "rf", &s) == -1 ? NULL : s;
1267 TF = cgetstr(bp, "tf", &s) == -1 ? NULL : s;
1268 NF = cgetstr(bp, "nf", &s) == -1 ? NULL : s;
1269 DF = cgetstr(bp, "df", &s) == -1 ? NULL : s;
1270 GF = cgetstr(bp, "gf", &s) == -1 ? NULL : s;
1271 VF = cgetstr(bp, "vf", &s) == -1 ? NULL : s;
1272 CF = cgetstr(bp, "cf", &s) == -1 ? NULL : s;
1273 PF = cgetstr(bp, "pf", &s) == -1 ? NULL : s;
1274 TR = cgetstr(bp, "tr", &s) == -1 ? NULL : s;
1275
1276 RS = (cgetcap(bp, "rs", ':') != NULL);
1277 SF = (cgetcap(bp, "sf", ':') != NULL);
1278 SH = (cgetcap(bp, "sh", ':') != NULL);
1279 SB = (cgetcap(bp, "sb", ':') != NULL);
1280 HL = (cgetcap(bp, "hl", ':') != NULL);
1281 RW = (cgetcap(bp, "rw", ':') != NULL);
1282
1283 cgetnum(bp, "br", &BR);
1284 if (cgetnum(bp, "fc", &FC) < 0)
1285 FC = 0;
1286 if (cgetnum(bp, "fs", &FS) < 0)
1287 FS = 0;
1288 if (cgetnum(bp, "xc", &XC) < 0)
1289 XC = 0;
1290 if (cgetnum(bp, "xs", &XS) < 0)
1291 XS = 0;
1292 MS = cgetstr(bp, "ms", &s) == -1 ? NULL : s;
1293
1294 tof = (cgetcap(bp, "fo", ':') == NULL);
1295 }
1296
1297 /*
1298 * Setup output filter - called once for local printer, or (if -r given to lpd)
1299 * once per file for remote printers
1300 */
1301 static void
1302 setup_ofilter(int check_rflag)
1303 {
1304 extern int rflag;
1305
1306 if (OF && (!remote || (check_rflag && rflag))) {
1307 int p[2];
1308 int i, nofile;
1309 const char *cp;
1310
1311 pipe(p);
1312 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1313 dup2(p[0], 0); /* pipe is std in */
1314 dup2(pfd, 1); /* printer is std out */
1315 closelog();
1316 nofile = sysconf(_SC_OPEN_MAX);
1317 for (i = 3; i < nofile; i++)
1318 (void)close(i);
1319 if ((cp = strrchr(OF, '/')) == NULL)
1320 cp = OF;
1321 else
1322 cp++;
1323 execl(OF, cp, width, length, 0);
1324 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1325 exit(1);
1326 }
1327 (void)close(p[0]); /* close input side */
1328 ofd = p[1]; /* use pipe for output */
1329 } else {
1330 ofd = pfd;
1331 ofilter = 0;
1332 }
1333 }
1334
1335 /*
1336 * Close the output filter and reset ofd back to the main pfd descriptor
1337 */
1338 static void
1339 close_ofilter(void)
1340 {
1341 int i;
1342
1343 if (ofilter) {
1344 kill(ofilter, SIGCONT); /* to be sure */
1345 (void)close(ofd);
1346 ofd = pfd;
1347 while ((i = wait(NULL)) > 0 && i != ofilter)
1348 ;
1349 ofilter = 0;
1350 }
1351 }
1352
1353 /*
1354 * Acquire line printer or remote connection.
1355 */
1356 static void
1357 openpr(void)
1358 {
1359 char *cp;
1360
1361 if (!remote && *LP) {
1362 if ((cp = strchr(LP, '@')))
1363 opennet(cp);
1364 else
1365 opentty();
1366 } else if (remote) {
1367 openrem();
1368 } else {
1369 syslog(LOG_ERR, "%s: no line printer device or host name",
1370 printer);
1371 exit(1);
1372 }
1373
1374 /*
1375 * Start up an output filter, if needed.
1376 */
1377 setup_ofilter(0);
1378 }
1379
1380 /*
1381 * Printer connected directly to the network
1382 * or to a terminal server on the net
1383 */
1384 static void
1385 opennet(char *cp)
1386 {
1387 int i;
1388 int resp, port;
1389 char save_ch;
1390
1391 save_ch = *cp;
1392 *cp = '\0';
1393 port = atoi(LP);
1394 if (port <= 0) {
1395 syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1396 exit(1);
1397 }
1398 *cp++ = save_ch;
1399
1400 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1401 resp = -1;
1402 pfd = getport(cp, port);
1403 if (pfd < 0 && errno == ECONNREFUSED)
1404 resp = 1;
1405 else if (pfd >= 0) {
1406 /*
1407 * need to delay a bit for rs232 lines
1408 * to stabilize in case printer is
1409 * connected via a terminal server
1410 */
1411 delay(500);
1412 break;
1413 }
1414 if (i == 1) {
1415 if (resp < 0)
1416 pstatus("waiting for %s to come up", LP);
1417 else
1418 pstatus("waiting for access to printer on %s", LP);
1419 }
1420 sleep(i);
1421 }
1422 pstatus("sending to %s port %d", cp, port);
1423 }
1424
1425 /*
1426 * Printer is connected to an RS232 port on this host
1427 */
1428 static void
1429 opentty(void)
1430 {
1431 int i;
1432
1433 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1434 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1435 if (pfd >= 0) {
1436 delay(500);
1437 break;
1438 }
1439 if (errno == ENOENT) {
1440 syslog(LOG_ERR, "%s: %m", LP);
1441 exit(1);
1442 }
1443 if (i == 1)
1444 pstatus("waiting for %s to become ready (offline ?)",
1445 printer);
1446 sleep(i);
1447 }
1448 if (isatty(pfd))
1449 setty();
1450 pstatus("%s is ready and printing", printer);
1451 }
1452
1453 /*
1454 * Printer is on a remote host
1455 */
1456 static void
1457 openrem(void)
1458 {
1459 int i, n;
1460 int resp;
1461 char *rmhost;
1462
1463 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1464 resp = -1;
1465 if ((rmhost = strchr(RM, '@')))
1466 pfd = getport(rmhost+1, atoi(RM));
1467 else
1468 pfd = getport(RM, 0);
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