printjob.c revision 1.16 1 /* $NetBSD: printjob.c,v 1.16 1997/10/05 15:12:14 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.16 1997/10/05 15:12:14 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, stb.st_size, file);
869 for (i = 0; ; i++) {
870 if (write(pfd, buf, amt) != amt ||
871 (resp = response()) < 0 || resp == '\1') {
872 (void)close(f);
873 return(REPRINT);
874 } else if (resp == '\0')
875 break;
876 if (i == 0)
877 pstatus("no space on remote; waiting for queue to drain");
878 if (i == 10)
879 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
880 printer, RM);
881 sleep(5 * 60);
882 }
883 if (i)
884 pstatus("sending to %s", RM);
885 sizerr = 0;
886 for (i = 0; i < stb.st_size; i += BUFSIZ) {
887 amt = BUFSIZ;
888 if (i + amt > stb.st_size)
889 amt = stb.st_size - i;
890 if (sizerr == 0 && read(f, buf, amt) != amt)
891 sizerr = 1;
892 if (write(pfd, buf, amt) != amt) {
893 (void)close(f);
894 return(REPRINT);
895 }
896 }
897
898 (void)close(f);
899 if (sizerr) {
900 syslog(LOG_INFO, "%s: %s: changed size", printer, file);
901 /* tell recvjob to ignore this file */
902 (void)write(pfd, "\1", 1);
903 return(ERROR);
904 }
905 if (write(pfd, "", 1) != 1 || response())
906 return(REPRINT);
907 return(OK);
908 }
909
910 /*
911 * Check to make sure there have been no errors and that both programs
912 * are in sync with eachother.
913 * Return non-zero if the connection was lost.
914 */
915 static char
916 response()
917 {
918 char resp;
919
920 if (read(pfd, &resp, 1) != 1) {
921 syslog(LOG_INFO, "%s: lost connection", printer);
922 return(-1);
923 }
924 return(resp);
925 }
926
927 /*
928 * Banner printing stuff
929 */
930 static void
931 banner(name1, name2)
932 char *name1, *name2;
933 {
934 time_t tvec;
935
936 time(&tvec);
937 if (!SF && !tof)
938 (void)write(ofd, FF, strlen(FF));
939 if (SB) { /* short banner only */
940 if (class[0]) {
941 (void)write(ofd, class, strlen(class));
942 (void)write(ofd, ":", 1);
943 }
944 (void)write(ofd, name1, strlen(name1));
945 (void)write(ofd, " Job: ", 7);
946 (void)write(ofd, name2, strlen(name2));
947 (void)write(ofd, " Date: ", 8);
948 (void)write(ofd, ctime(&tvec), 24);
949 (void)write(ofd, "\n", 1);
950 } else { /* normal banner */
951 (void)write(ofd, "\n\n\n", 3);
952 scan_out(ofd, name1, '\0');
953 (void)write(ofd, "\n\n", 2);
954 scan_out(ofd, name2, '\0');
955 if (class[0]) {
956 (void)write(ofd,"\n\n\n",3);
957 scan_out(ofd, class, '\0');
958 }
959 (void)write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
960 (void)write(ofd, name2, strlen(name2));
961 (void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
962 (void)write(ofd, ctime(&tvec), 24);
963 (void)write(ofd, "\n", 1);
964 }
965 if (!SF)
966 (void)write(ofd, FF, strlen(FF));
967 tof = 1;
968 }
969
970 static char *
971 scnline(key, p, c)
972 int key;
973 char *p;
974 int c;
975 {
976 int scnwidth;
977
978 for (scnwidth = WIDTH; --scnwidth;) {
979 key <<= 1;
980 *p++ = key & 0200 ? c : BACKGND;
981 }
982 return (p);
983 }
984
985 #define TRC(q) (((q)-' ')&0177)
986
987 static void
988 scan_out(scfd, scsp, dlm)
989 int scfd, dlm;
990 char *scsp;
991 {
992 char *strp;
993 int nchrs, j;
994 char outbuf[LINELEN+1], *sp, c, cc;
995 int d, scnhgt;
996 extern char scnkey[][HEIGHT]; /* in lpdchar.c */
997
998 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
999 strp = &outbuf[0];
1000 sp = scsp;
1001 for (nchrs = 0; ; ) {
1002 d = dropit(c = TRC(cc = *sp++));
1003 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1004 for (j = WIDTH; --j;)
1005 *strp++ = BACKGND;
1006 else
1007 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1008 strp, cc);
1009 if (*sp == dlm || *sp == '\0' ||
1010 nchrs++ >= PW/(WIDTH+1)-1)
1011 break;
1012 *strp++ = BACKGND;
1013 *strp++ = BACKGND;
1014 }
1015 while (*--strp == BACKGND && strp >= outbuf)
1016 ;
1017 strp++;
1018 *strp++ = '\n';
1019 (void)write(scfd, outbuf, strp-outbuf);
1020 }
1021 }
1022
1023 static int
1024 dropit(c)
1025 int c;
1026 {
1027 switch(c) {
1028
1029 case TRC('_'):
1030 case TRC(';'):
1031 case TRC(','):
1032 case TRC('g'):
1033 case TRC('j'):
1034 case TRC('p'):
1035 case TRC('q'):
1036 case TRC('y'):
1037 return (DROP);
1038
1039 default:
1040 return (0);
1041 }
1042 }
1043
1044 /*
1045 * sendmail ---
1046 * tell people about job completion
1047 */
1048 static void
1049 sendmail(user, bombed)
1050 char *user;
1051 int bombed;
1052 {
1053 int i, p[2], s, nofile;
1054 char *cp = NULL; /* XXX gcc */
1055 struct stat stb;
1056 FILE *fp;
1057
1058 if (user[0] == '-' || user[0] == '/' || !isprint(user[0]))
1059 return;
1060 pipe(p);
1061 if ((s = dofork(DORETURN)) == 0) { /* child */
1062 dup2(p[0], 0);
1063 closelog();
1064 nofile = sysconf(_SC_OPEN_MAX);
1065 for (i = 3; i < nofile; i++)
1066 (void)close(i);
1067 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1068 cp++;
1069 else
1070 cp = _PATH_SENDMAIL;
1071 execl(_PATH_SENDMAIL, cp, "-t", 0);
1072 exit(0);
1073 } else if (s > 0) { /* parent */
1074 dup2(p[1], 1);
1075 printf("To: %s@%s\n", user, fromhost);
1076 printf("Subject: %s printer job \"%s\"\n", printer,
1077 *jobname ? jobname : "<unknown>");
1078 printf("Reply-To: root@%s\n\n", host);
1079 printf("Your printer job ");
1080 if (*jobname)
1081 printf("(%s) ", jobname);
1082 switch (bombed) {
1083 case OK:
1084 printf("\ncompleted successfully\n");
1085 cp = "OK";
1086 break;
1087 default:
1088 case FATALERR:
1089 printf("\ncould not be printed\n");
1090 cp = "FATALERR";
1091 break;
1092 case NOACCT:
1093 printf("\ncould not be printed without an account on %s\n", host);
1094 cp = "NOACCT";
1095 break;
1096 case FILTERERR:
1097 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1098 (fp = fopen(tempfile, "r")) == NULL) {
1099 printf("\nhad some errors and may not have printed\n");
1100 break;
1101 }
1102 printf("\nhad the following errors and may not have printed:\n");
1103 while ((i = getc(fp)) != EOF)
1104 putchar(i);
1105 (void)fclose(fp);
1106 cp = "FILTERERR";
1107 break;
1108 case ACCESS:
1109 printf("\nwas not printed because it was not linked to the original file\n");
1110 cp = "ACCESS";
1111 }
1112 fflush(stdout);
1113 (void)close(1);
1114 } else {
1115 syslog(LOG_ERR, "fork for sendmail failed: %m");
1116 }
1117 (void)close(p[0]);
1118 (void)close(p[1]);
1119 if (s > 0) {
1120 wait(NULL);
1121 syslog(LOG_INFO, "mail sent to user %s about job %s on "
1122 "printer %s (%s)", user, *jobname ? jobname : "<unknown>",
1123 printer, cp);
1124 }
1125 }
1126
1127 /*
1128 * dofork - fork with retries on failure
1129 */
1130 static int
1131 dofork(action)
1132 int action;
1133 {
1134 int i, pid;
1135 struct passwd *pw;
1136
1137 for (i = 0; i < 20; i++) {
1138 if ((pid = fork()) < 0) {
1139 sleep((unsigned)(i*i));
1140 continue;
1141 }
1142 /*
1143 * Child should run as daemon instead of root
1144 */
1145 if (pid == 0) {
1146 pw = getpwuid(DU);
1147 if (pw == 0) {
1148 syslog(LOG_ERR, "uid %ld not in password file",
1149 DU);
1150 break;
1151 }
1152 initgroups(pw->pw_name, pw->pw_gid);
1153 setgid(pw->pw_gid);
1154 setuid(DU);
1155 }
1156 return (pid);
1157 }
1158 syslog(LOG_ERR, "can't fork");
1159
1160 switch (action) {
1161 case DORETURN:
1162 return (-1);
1163 default:
1164 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1165 /*FALL THRU*/
1166 case DOABORT:
1167 exit(1);
1168 }
1169 /*NOTREACHED*/
1170 }
1171
1172 /*
1173 * Kill child processes to abort current job.
1174 */
1175 static void
1176 abortpr(signo)
1177 int signo;
1178 {
1179 (void)unlink(tempfile);
1180 kill(0, SIGINT);
1181 if (ofilter > 0)
1182 kill(ofilter, SIGCONT);
1183 while (wait(NULL) > 0)
1184 ;
1185 exit(0);
1186 }
1187
1188 static void
1189 init()
1190 {
1191 int status;
1192 char *s;
1193
1194 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1195 syslog(LOG_ERR, "can't open printer description file");
1196 exit(1);
1197 } else if (status == -1) {
1198 syslog(LOG_ERR, "unknown printer: %s", printer);
1199 exit(1);
1200 } else if (status == -3)
1201 fatal("potential reference loop detected in printcap file");
1202
1203 if (cgetstr(bp, "lp", &LP) == -1)
1204 LP = _PATH_DEFDEVLP;
1205 if (cgetstr(bp, "rp", &RP) == -1)
1206 RP = DEFLP;
1207 if (cgetstr(bp, "lo", &LO) == -1)
1208 LO = DEFLOCK;
1209 if (cgetstr(bp, "st", &ST) == -1)
1210 ST = DEFSTAT;
1211 if (cgetstr(bp, "lf", &LF) == -1)
1212 LF = _PATH_CONSOLE;
1213 if (cgetstr(bp, "sd", &SD) == -1)
1214 SD = _PATH_DEFSPOOL;
1215 if (cgetnum(bp, "du", &DU) < 0)
1216 DU = DEFUID;
1217 if (cgetstr(bp,"ff", &FF) == -1)
1218 FF = DEFFF;
1219 if (cgetnum(bp, "pw", &PW) < 0)
1220 PW = DEFWIDTH;
1221 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1222 if (cgetnum(bp, "pl", &PL) < 0)
1223 PL = DEFLENGTH;
1224 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1225 if (cgetnum(bp,"px", &PX) < 0)
1226 PX = 0;
1227 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1228 if (cgetnum(bp, "py", &PY) < 0)
1229 PY = 0;
1230 (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
1231 cgetstr(bp, "rm", &RM);
1232 if ((s = checkremote()) != NULL)
1233 syslog(LOG_WARNING, s);
1234
1235 cgetstr(bp, "af", &AF);
1236 cgetstr(bp, "of", &OF);
1237 cgetstr(bp, "if", &IF);
1238 cgetstr(bp, "rf", &RF);
1239 cgetstr(bp, "tf", &TF);
1240 cgetstr(bp, "nf", &NF);
1241 cgetstr(bp, "df", &DF);
1242 cgetstr(bp, "gf", &GF);
1243 cgetstr(bp, "vf", &VF);
1244 cgetstr(bp, "cf", &CF);
1245 cgetstr(bp, "tr", &TR);
1246
1247 RS = (cgetcap(bp, "rs", ':') != NULL);
1248 SF = (cgetcap(bp, "sf", ':') != NULL);
1249 SH = (cgetcap(bp, "sh", ':') != NULL);
1250 SB = (cgetcap(bp, "sb", ':') != NULL);
1251 HL = (cgetcap(bp, "hl", ':') != NULL);
1252 RW = (cgetcap(bp, "rw", ':') != NULL);
1253
1254 cgetnum(bp, "br", &BR);
1255 if (cgetnum(bp, "fc", &FC) < 0)
1256 FC = 0;
1257 if (cgetnum(bp, "fs", &FS) < 0)
1258 FS = 0;
1259 if (cgetnum(bp, "xc", &XC) < 0)
1260 XC = 0;
1261 if (cgetnum(bp, "xs", &XS) < 0)
1262 XS = 0;
1263 cgetstr(bp, "ms", &MS);
1264
1265 tof = (cgetcap(bp, "fo", ':') == NULL);
1266 }
1267
1268 /*
1269 * Acquire line printer or remote connection.
1270 */
1271 static void
1272 openpr()
1273 {
1274 int i, nofile;
1275 char *cp;
1276
1277 if (!remote && *LP) {
1278 if ((cp = strchr(LP, '@')))
1279 opennet(cp);
1280 else
1281 opentty();
1282 } else if (remote) {
1283 openrem();
1284 } else {
1285 syslog(LOG_ERR, "%s: no line printer device or host name",
1286 printer);
1287 exit(1);
1288 }
1289
1290 /*
1291 * Start up an output filter, if needed.
1292 */
1293 if (!remote && OF) {
1294 int p[2];
1295
1296 pipe(p);
1297 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1298 dup2(p[0], 0); /* pipe is std in */
1299 dup2(pfd, 1); /* printer is std out */
1300 closelog();
1301 nofile = sysconf(_SC_OPEN_MAX);
1302 for (i = 3; i < nofile; i++)
1303 (void)close(i);
1304 if ((cp = strrchr(OF, '/')) == NULL)
1305 cp = OF;
1306 else
1307 cp++;
1308 execl(OF, cp, width, length, 0);
1309 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1310 exit(1);
1311 }
1312 (void)close(p[0]); /* close input side */
1313 ofd = p[1]; /* use pipe for output */
1314 } else {
1315 ofd = pfd;
1316 ofilter = 0;
1317 }
1318 }
1319
1320 /*
1321 * Printer connected directly to the network
1322 * or to a terminal server on the net
1323 */
1324 static void
1325 opennet(cp)
1326 char *cp;
1327 {
1328 int i;
1329 int resp, port;
1330 char save_ch;
1331
1332 save_ch = *cp;
1333 *cp = '\0';
1334 port = atoi(LP);
1335 if (port <= 0) {
1336 syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1337 exit(1);
1338 }
1339 *cp++ = save_ch;
1340
1341 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1342 resp = -1;
1343 pfd = getport(cp, port);
1344 if (pfd < 0 && errno == ECONNREFUSED)
1345 resp = 1;
1346 else if (pfd >= 0) {
1347 /*
1348 * need to delay a bit for rs232 lines
1349 * to stabilize in case printer is
1350 * connected via a terminal server
1351 */
1352 delay(500);
1353 break;
1354 }
1355 if (i == 1) {
1356 if (resp < 0)
1357 pstatus("waiting for %s to come up", LP);
1358 else
1359 pstatus("waiting for access to printer on %s", LP);
1360 }
1361 sleep(i);
1362 }
1363 pstatus("sending to %s port %d", cp, port);
1364 }
1365
1366 /*
1367 * Printer is connected to an RS232 port on this host
1368 */
1369 static void
1370 opentty()
1371 {
1372 int i;
1373
1374 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1375 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1376 if (pfd >= 0) {
1377 delay(500);
1378 break;
1379 }
1380 if (errno == ENOENT) {
1381 syslog(LOG_ERR, "%s: %m", LP);
1382 exit(1);
1383 }
1384 if (i == 1)
1385 pstatus("waiting for %s to become ready (offline ?)",
1386 printer);
1387 sleep(i);
1388 }
1389 if (isatty(pfd))
1390 setty();
1391 pstatus("%s is ready and printing", printer);
1392 }
1393
1394 /*
1395 * Printer is on a remote host
1396 */
1397 static void
1398 openrem()
1399 {
1400 int i, n;
1401 int resp;
1402
1403 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1404 resp = -1;
1405 pfd = getport(RM, 0);
1406 if (pfd >= 0) {
1407 n = snprintf(line, sizeof(line), "\2%s\n", RP);
1408 if (write(pfd, line, n) == n &&
1409 (resp = response()) == '\0')
1410 break;
1411 (void) close(pfd);
1412 }
1413 if (i == 1) {
1414 if (resp < 0)
1415 pstatus("waiting for %s to come up", RM);
1416 else {
1417 pstatus("waiting for queue to be enabled on %s",
1418 RM);
1419 i = 256;
1420 }
1421 }
1422 sleep(i);
1423 }
1424 pstatus("sending to %s", RM);
1425 }
1426
1427 #if !defined(__NetBSD__)
1428 struct bauds {
1429 int baud;
1430 int speed;
1431 } bauds[] = {
1432 50, B50,
1433 75, B75,
1434 110, B110,
1435 134, B134,
1436 150, B150,
1437 200, B200,
1438 300, B300,
1439 600, B600,
1440 1200, B1200,
1441 1800, B1800,
1442 2400, B2400,
1443 4800, B4800,
1444 9600, B9600,
1445 19200, B19200,
1446 38400, B38400,
1447 57600, B57600,
1448 115200, B115200,
1449 0, 0
1450 };
1451 #endif
1452
1453 /*
1454 * setup tty lines.
1455 */
1456 static void
1457 setty()
1458 {
1459 struct info i;
1460 char **argv, **ap, *p, *val;
1461
1462 i.fd = pfd;
1463 i.set = i.wset = 0;
1464 if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
1465 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1466 exit(1);
1467 }
1468 if (tcgetattr(i.fd, &i.t) < 0) {
1469 syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1470 exit(1);
1471 }
1472 if (BR > 0) {
1473 #if !defined(__NetBSD__)
1474 struct bauds *bp;
1475 for (bp = bauds; bp->baud; bp++)
1476 if (BR == bp->baud)
1477 break;
1478 if (!bp->baud) {
1479 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1480 exit(1);
1481 }
1482 cfsetspeed(&i.t, bp->speed);
1483 #else
1484 cfsetspeed(&i.t, BR);
1485 #endif
1486 i.set = 1;
1487 }
1488 if (MS) {
1489 if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
1490 syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
1491 exit(1);
1492 }
1493 if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
1494 syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
1495 printer);
1496
1497 argv = (char **)calloc(256, sizeof(char *));
1498 if (argv == NULL) {
1499 syslog(LOG_ERR, "%s: calloc: %m", printer);
1500 exit(1);
1501 }
1502 p = strdup(MS);
1503 ap = argv;
1504 while ((val = strsep(&p, " \t,")) != NULL) {
1505 *ap++ = strdup(val);
1506 }
1507
1508 for (; *argv; ++argv) {
1509 if (ksearch(&argv, &i))
1510 continue;
1511 if (msearch(&argv, &i))
1512 continue;
1513 syslog(LOG_INFO, "%s: unknown stty flag: %s",
1514 printer, *argv);
1515 }
1516 } else {
1517 if (FC) {
1518 sttyclearflags(&i.t, FC);
1519 i.set = 1;
1520 }
1521 if (FS) {
1522 sttysetflags(&i.t, FS);
1523 i.set = 1;
1524 }
1525 if (XC) {
1526 sttyclearlflags(&i.t, XC);
1527 i.set = 1;
1528 }
1529 if (XS) {
1530 sttysetlflags(&i.t, XS);
1531 i.set = 1;
1532 }
1533 }
1534
1535 if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
1536 syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1537 exit(1);
1538 }
1539 if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
1540 syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
1541 return;
1542 }
1543
1544 #ifdef __STDC__
1545 #include <stdarg.h>
1546 #else
1547 #include <varargs.h>
1548 #endif
1549
1550 static void
1551 #ifdef __STDC__
1552 pstatus(const char *msg, ...)
1553 #else
1554 pstatus(msg, va_alist)
1555 char *msg;
1556 va_dcl
1557 #endif
1558 {
1559 int fd;
1560 char buf[BUFSIZ];
1561 va_list ap;
1562 #ifdef __STDC__
1563 va_start(ap, msg);
1564 #else
1565 va_start(ap);
1566 #endif
1567
1568 umask(0);
1569 fd = open(ST, O_WRONLY|O_CREAT, 0664);
1570 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1571 syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1572 exit(1);
1573 }
1574 ftruncate(fd, 0);
1575 (void)vsnprintf(buf, sizeof(buf) - 2, msg, ap);
1576 va_end(ap);
1577 strncat(buf, "\n", 2);
1578 (void)write(fd, buf, strlen(buf));
1579 (void)close(fd);
1580 }
1581