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