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