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