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