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