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