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