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