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