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