printjob.c revision 1.20 1 /* $NetBSD: printjob.c,v 1.20 1999/09/26 10:32:28 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.20 1999/09/26 10:32:28 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); /* OK */
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 class[sizeof(class) - 1] = '\0';
430 }
431 continue;
432
433 case 'T': /* header title for pr */
434 strncpy(title, line+1, sizeof(title) - 1);
435 title[sizeof(title)-1] = '\0';
436 continue;
437
438 case 'L': /* identification line */
439 if (!SH && !HL)
440 banner(line+1, jobname);
441 continue;
442
443 case '1': /* troff fonts */
444 case '2':
445 case '3':
446 case '4':
447 if (line[1] != '\0') {
448 strncpy(fonts[line[0]-'1'], line+1, FONTLEN - 1);
449 fonts[line[0]-'1'][50-1] = '\0';
450 }
451 continue;
452
453 case 'W': /* page width */
454 strncpy(width+2, line+1, sizeof(width) - 3);
455 width[sizeof(width)-1] = '\0';
456 continue;
457
458 case 'I': /* indent amount */
459 strncpy(indent+2, line+1, sizeof(indent) - 3);
460 indent[sizeof(indent)-1] = '\0';
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 occured,
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(format, file)
528 int format;
529 char *file;
530 {
531 FILE *fp;
532 int status;
533 struct stat stb;
534 char *prog, *av[15], buf[BUFSIZ];
535 int n, fi, fo, pid, p[2], stopped = 0, nofile;
536
537 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
538 return(ERROR);
539 /*
540 * Check to see if data file is a symbolic link. If so, it should
541 * still point to the same file or someone is trying to print
542 * something he shouldn't.
543 */
544 if (S_ISLNK(stb.st_mode) && fstat(fi, &stb) == 0 &&
545 (stb.st_dev != fdev || stb.st_ino != fino))
546 return(ACCESS);
547 if (!SF && !tof) { /* start on a fresh page */
548 (void)write(ofd, FF, strlen(FF));
549 tof = 1;
550 }
551 if (IF == NULL && (format == 'f' || format == 'l')) {
552 tof = 0;
553 while ((n = read(fi, buf, BUFSIZ)) > 0)
554 if (write(ofd, buf, n) != n) {
555 (void)close(fi);
556 return(REPRINT);
557 }
558 (void)close(fi);
559 return(OK);
560 }
561 switch (format) {
562 case 'p': /* print file using 'pr' */
563 if (IF == NULL) { /* use output filter */
564 prog = _PATH_PR;
565 av[0] = "pr";
566 av[1] = width;
567 av[2] = length;
568 av[3] = "-h";
569 av[4] = *title ? title : " ";
570 av[5] = 0;
571 fo = ofd;
572 goto start;
573 }
574 pipe(p);
575 if ((prchild = dofork(DORETURN)) == 0) { /* child */
576 dup2(fi, 0); /* file is stdin */
577 dup2(p[1], 1); /* pipe is stdout */
578 closelog();
579 nofile = sysconf(_SC_OPEN_MAX);
580 for (n = 3; n < nofile; n++)
581 (void)close(n);
582 execl(_PATH_PR, "pr", width, length,
583 "-h", *title ? title : " ", 0);
584 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
585 exit(2);
586 }
587 (void)close(p[1]); /* close output side */
588 (void)close(fi);
589 if (prchild < 0) {
590 prchild = 0;
591 (void)close(p[0]);
592 return(ERROR);
593 }
594 fi = p[0]; /* use pipe for input */
595 case 'f': /* print plain text file */
596 prog = IF;
597 av[1] = width;
598 av[2] = length;
599 av[3] = indent;
600 n = 4;
601 break;
602 case 'l': /* like 'f' but pass control characters */
603 prog = IF;
604 av[1] = "-c";
605 av[2] = width;
606 av[3] = length;
607 av[4] = indent;
608 n = 5;
609 break;
610 case 'r': /* print a fortran text file */
611 prog = RF;
612 av[1] = width;
613 av[2] = length;
614 n = 3;
615 break;
616 case 't': /* print troff output */
617 case 'n': /* print ditroff output */
618 case 'd': /* print tex output */
619 (void)unlink(".railmag");
620 if ((fo = creat(".railmag", FILMOD)) < 0) {
621 syslog(LOG_ERR, "%s: cannot create .railmag", printer);
622 (void)unlink(".railmag");
623 } else {
624 for (n = 0; n < 4; n++) {
625 if (fonts[n][0] != '/')
626 (void)write(fo, _PATH_VFONT,
627 sizeof(_PATH_VFONT) - 1);
628 (void)write(fo, fonts[n], strlen(fonts[n]));
629 (void)write(fo, "\n", 1);
630 }
631 (void)close(fo);
632 }
633 prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
634 av[1] = pxwidth;
635 av[2] = pxlength;
636 n = 3;
637 break;
638 case 'c': /* print cifplot output */
639 prog = CF;
640 av[1] = pxwidth;
641 av[2] = pxlength;
642 n = 3;
643 break;
644 case 'g': /* print plot(1G) output */
645 prog = GF;
646 av[1] = pxwidth;
647 av[2] = pxlength;
648 n = 3;
649 break;
650 case 'v': /* print raster output */
651 prog = VF;
652 av[1] = pxwidth;
653 av[2] = pxlength;
654 n = 3;
655 break;
656 default:
657 (void)close(fi);
658 syslog(LOG_ERR, "%s: illegal format character '%c'",
659 printer, format);
660 return(ERROR);
661 }
662 if (prog == NULL) {
663 (void)close(fi);
664 syslog(LOG_ERR,
665 "%s: no filter found in printcap for format character '%c'",
666 printer, format);
667 return (ERROR);
668 }
669 if ((av[0] = strrchr(prog, '/')) != NULL)
670 av[0]++;
671 else
672 av[0] = prog;
673 av[n++] = "-n";
674 av[n++] = logname;
675 av[n++] = "-h";
676 av[n++] = fromhost;
677 av[n++] = AF;
678 av[n] = 0;
679 fo = pfd;
680 if (ofilter > 0) { /* stop output filter */
681 write(ofd, "\031\1", 2);
682 while ((pid =
683 wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
684 ;
685 if (WIFSTOPPED(status) == 0) {
686 (void)close(fi);
687 syslog(LOG_WARNING,
688 "%s: output filter died (retcode=%d termsig=%d)",
689 printer, WEXITSTATUS(status), WTERMSIG(status));
690 return(REPRINT);
691 }
692 stopped++;
693 }
694 start:
695 if ((child = dofork(DORETURN)) == 0) { /* child */
696 dup2(fi, 0);
697 dup2(fo, 1);
698 unlink(tempfile);
699 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
700 if (n >= 0)
701 dup2(n, 2);
702 closelog();
703 nofile = sysconf(_SC_OPEN_MAX);
704 for (n = 3; n < nofile; n++)
705 (void)close(n);
706 execv(prog, av);
707 syslog(LOG_ERR, "cannot execv %s", prog);
708 exit(2);
709 }
710 if (child < 0) {
711 child = 0;
712 prchild = 0;
713 tof = 0;
714 syslog(LOG_ERR, "cannot start child process: %m");
715 return (ERROR);
716 }
717 (void)close(fi);
718 while ((pid = wait(&status)) > 0 && pid != child)
719 ;
720 child = 0;
721 prchild = 0;
722 if (stopped) { /* restart output filter */
723 if (kill(ofilter, SIGCONT) < 0) {
724 syslog(LOG_ERR, "cannot restart output filter");
725 exit(1);
726 }
727 }
728 tof = 0;
729
730 /* Copy filter output to "lf" logfile */
731 if ((fp = fopen(tempfile, "r")) != NULL) {
732 while (fgets(buf, sizeof(buf), fp))
733 fputs(buf, stderr);
734 fclose(fp);
735 }
736
737 if (!WIFEXITED(status)) {
738 syslog(LOG_WARNING,
739 "%s: Daemon filter '%c' terminated (termsig=%d)",
740 printer, format, WTERMSIG(status));
741 return(ERROR);
742 }
743 switch (WEXITSTATUS(status)) {
744 case 0:
745 tof = 1;
746 return(OK);
747 case 1:
748 return(REPRINT);
749 case 2:
750 return(ERROR);
751 default:
752 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
753 printer, format, WEXITSTATUS(status));
754 return(FILTERERR);
755 }
756 }
757
758 /*
759 * Send the daemon control file (cf) and any data files.
760 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
761 * 0 if all is well.
762 */
763 static int
764 sendit(file)
765 char *file;
766 {
767 int i, err = OK;
768 char *cp, last[BUFSIZ];
769
770 /*
771 * open control file
772 */
773 if ((cfp = fopen(file, "r")) == NULL)
774 return(OK);
775 /*
776 * read the control file for work to do
777 *
778 * file format -- first character in the line is a command
779 * rest of the line is the argument.
780 * commands of interest are:
781 *
782 * a-z -- "file name" name of file to print
783 * U -- "unlink" name of file to remove
784 * (after we print it. (Pass 2 only)).
785 */
786
787 /*
788 * pass 1
789 */
790 while (getline(cfp)) {
791 again:
792 if (line[0] == 'S') {
793 cp = line+1;
794 i = 0;
795 while (*cp >= '0' && *cp <= '9')
796 i = i * 10 + (*cp++ - '0');
797 fdev = i;
798 cp++;
799 i = 0;
800 while (*cp >= '0' && *cp <= '9')
801 i = i * 10 + (*cp++ - '0');
802 fino = i;
803 continue;
804 }
805 if (line[0] >= 'a' && line[0] <= 'z') {
806 strncpy(last, line, sizeof(last) - 1);
807 last[sizeof(last) - 1] = '\0';
808 while ((i = getline(cfp)) != 0)
809 if (strcmp(last, line))
810 break;
811 switch (sendfile('\3', last+1)) {
812 case OK:
813 if (i)
814 goto again;
815 break;
816 case REPRINT:
817 (void)fclose(cfp);
818 return(REPRINT);
819 case ACCESS:
820 sendmail(logname, ACCESS);
821 case ERROR:
822 err = ERROR;
823 }
824 break;
825 }
826 }
827 if (err == OK && sendfile('\2', file) > 0) {
828 (void)fclose(cfp);
829 return(REPRINT);
830 }
831 /*
832 * pass 2
833 */
834 fseek(cfp, 0L, 0);
835 while (getline(cfp))
836 if (line[0] == 'U' && strchr(line+1, '/') == 0)
837 (void)unlink(line+1);
838 /*
839 * clean-up in case another control file exists
840 */
841 (void)fclose(cfp);
842 (void)unlink(file);
843 return(err);
844 }
845
846 /*
847 * Send a data file to the remote machine and spool it.
848 * Return positive if we should try resending.
849 */
850 static int
851 sendfile(type, file)
852 int type;
853 char *file;
854 {
855 int f, i, amt;
856 struct stat stb;
857 char buf[BUFSIZ];
858 int sizerr, resp;
859
860 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
861 return(ERROR);
862 /*
863 * Check to see if data file is a symbolic link. If so, it should
864 * still point to the same file or someone is trying to print something
865 * he shouldn't.
866 */
867 if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
868 (stb.st_dev != fdev || stb.st_ino != fino))
869 return(ACCESS);
870 amt = snprintf(buf, sizeof(buf), "%c%qd %s\n", type,
871 (long long)stb.st_size, file);
872 for (i = 0; ; i++) {
873 if (write(pfd, buf, amt) != amt ||
874 (resp = response()) < 0 || resp == '\1') {
875 (void)close(f);
876 return(REPRINT);
877 } else if (resp == '\0')
878 break;
879 if (i == 0)
880 pstatus("no space on remote; waiting for queue to drain");
881 if (i == 10)
882 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
883 printer, RM);
884 sleep(5 * 60);
885 }
886 if (i)
887 pstatus("sending to %s", RM);
888 sizerr = 0;
889 for (i = 0; i < stb.st_size; i += BUFSIZ) {
890 amt = BUFSIZ;
891 if (i + amt > stb.st_size)
892 amt = stb.st_size - i;
893 if (sizerr == 0 && read(f, buf, amt) != amt)
894 sizerr = 1;
895 if (write(pfd, buf, amt) != amt) {
896 (void)close(f);
897 return(REPRINT);
898 }
899 }
900
901 (void)close(f);
902 if (sizerr) {
903 syslog(LOG_INFO, "%s: %s: changed size", printer, file);
904 /* tell recvjob to ignore this file */
905 (void)write(pfd, "\1", 1);
906 return(ERROR);
907 }
908 if (write(pfd, "", 1) != 1 || response())
909 return(REPRINT);
910 return(OK);
911 }
912
913 /*
914 * Check to make sure there have been no errors and that both programs
915 * are in sync with eachother.
916 * Return non-zero if the connection was lost.
917 */
918 static char
919 response()
920 {
921 char resp;
922
923 if (read(pfd, &resp, 1) != 1) {
924 syslog(LOG_INFO, "%s: lost connection", printer);
925 return(-1);
926 }
927 return(resp);
928 }
929
930 /*
931 * Banner printing stuff
932 */
933 static void
934 banner(name1, name2)
935 char *name1, *name2;
936 {
937 time_t tvec;
938
939 time(&tvec);
940 if (!SF && !tof)
941 (void)write(ofd, FF, strlen(FF));
942 if (SB) { /* short banner only */
943 if (class[0]) {
944 (void)write(ofd, class, strlen(class));
945 (void)write(ofd, ":", 1);
946 }
947 (void)write(ofd, name1, strlen(name1));
948 (void)write(ofd, " Job: ", 7);
949 (void)write(ofd, name2, strlen(name2));
950 (void)write(ofd, " Date: ", 8);
951 (void)write(ofd, ctime(&tvec), 24);
952 (void)write(ofd, "\n", 1);
953 } else { /* normal banner */
954 (void)write(ofd, "\n\n\n", 3);
955 scan_out(ofd, name1, '\0');
956 (void)write(ofd, "\n\n", 2);
957 scan_out(ofd, name2, '\0');
958 if (class[0]) {
959 (void)write(ofd,"\n\n\n",3);
960 scan_out(ofd, class, '\0');
961 }
962 (void)write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
963 (void)write(ofd, name2, strlen(name2));
964 (void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
965 (void)write(ofd, ctime(&tvec), 24);
966 (void)write(ofd, "\n", 1);
967 }
968 if (!SF)
969 (void)write(ofd, FF, strlen(FF));
970 tof = 1;
971 }
972
973 static char *
974 scnline(key, p, c)
975 int key;
976 char *p;
977 int c;
978 {
979 int scnwidth;
980
981 for (scnwidth = WIDTH; --scnwidth;) {
982 key <<= 1;
983 *p++ = key & 0200 ? c : BACKGND;
984 }
985 return (p);
986 }
987
988 #define TRC(q) (((q)-' ')&0177)
989
990 static void
991 scan_out(scfd, scsp, dlm)
992 int scfd, dlm;
993 char *scsp;
994 {
995 char *strp;
996 int nchrs, j;
997 char outbuf[LINELEN+1], *sp, c, cc;
998 int d, scnhgt;
999 extern char scnkey[][HEIGHT]; /* in lpdchar.c */
1000
1001 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1002 strp = &outbuf[0];
1003 sp = scsp;
1004 for (nchrs = 0; ; ) {
1005 d = dropit(c = TRC(cc = *sp++));
1006 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1007 for (j = WIDTH; --j;)
1008 *strp++ = BACKGND;
1009 else
1010 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1011 strp, cc);
1012 if (*sp == dlm || *sp == '\0' ||
1013 nchrs++ >= PW/(WIDTH+1)-1)
1014 break;
1015 *strp++ = BACKGND;
1016 *strp++ = BACKGND;
1017 }
1018 while (*--strp == BACKGND && strp >= outbuf)
1019 ;
1020 strp++;
1021 *strp++ = '\n';
1022 (void)write(scfd, outbuf, strp-outbuf);
1023 }
1024 }
1025
1026 static int
1027 dropit(c)
1028 int c;
1029 {
1030 switch(c) {
1031
1032 case TRC('_'):
1033 case TRC(';'):
1034 case TRC(','):
1035 case TRC('g'):
1036 case TRC('j'):
1037 case TRC('p'):
1038 case TRC('q'):
1039 case TRC('y'):
1040 return (DROP);
1041
1042 default:
1043 return (0);
1044 }
1045 }
1046
1047 /*
1048 * sendmail ---
1049 * tell people about job completion
1050 */
1051 static void
1052 sendmail(user, bombed)
1053 char *user;
1054 int bombed;
1055 {
1056 int i, p[2], s, nofile;
1057 char *cp = NULL; /* XXX gcc */
1058 struct stat stb;
1059 FILE *fp;
1060
1061 if (user[0] == '-' || user[0] == '/' || !isprint(user[0]))
1062 return;
1063 pipe(p);
1064 if ((s = dofork(DORETURN)) == 0) { /* child */
1065 dup2(p[0], 0);
1066 closelog();
1067 nofile = sysconf(_SC_OPEN_MAX);
1068 for (i = 3; i < nofile; i++)
1069 (void)close(i);
1070 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1071 cp++;
1072 else
1073 cp = _PATH_SENDMAIL;
1074 execl(_PATH_SENDMAIL, cp, "-t", 0);
1075 exit(0);
1076 } else if (s > 0) { /* parent */
1077 dup2(p[1], 1);
1078 printf("To: %s@%s\n", user, fromhost);
1079 printf("Subject: %s printer job \"%s\"\n", printer,
1080 *jobname ? jobname : "<unknown>");
1081 printf("Reply-To: root@%s\n\n", host);
1082 printf("Your printer job ");
1083 if (*jobname)
1084 printf("(%s) ", jobname);
1085 switch (bombed) {
1086 case OK:
1087 printf("\ncompleted successfully\n");
1088 cp = "OK";
1089 break;
1090 default:
1091 case FATALERR:
1092 printf("\ncould not be printed\n");
1093 cp = "FATALERR";
1094 break;
1095 case NOACCT:
1096 printf("\ncould not be printed without an account on %s\n", host);
1097 cp = "NOACCT";
1098 break;
1099 case FILTERERR:
1100 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1101 (fp = fopen(tempfile, "r")) == NULL) {
1102 printf("\nhad some errors and may not have printed\n");
1103 break;
1104 }
1105 printf("\nhad the following errors and may not have printed:\n");
1106 while ((i = getc(fp)) != EOF)
1107 putchar(i);
1108 (void)fclose(fp);
1109 cp = "FILTERERR";
1110 break;
1111 case ACCESS:
1112 printf("\nwas not printed because it was not linked to the original file\n");
1113 cp = "ACCESS";
1114 }
1115 fflush(stdout);
1116 (void)close(1);
1117 } else {
1118 syslog(LOG_ERR, "fork for sendmail failed: %m");
1119 }
1120 (void)close(p[0]);
1121 (void)close(p[1]);
1122 if (s > 0) {
1123 wait(NULL);
1124 syslog(LOG_INFO, "mail sent to user %s about job %s on "
1125 "printer %s (%s)", user, *jobname ? jobname : "<unknown>",
1126 printer, cp);
1127 }
1128 }
1129
1130 /*
1131 * dofork - fork with retries on failure
1132 */
1133 static int
1134 dofork(action)
1135 int action;
1136 {
1137 int i, pid;
1138 struct passwd *pw;
1139
1140 for (i = 0; i < 20; i++) {
1141 if ((pid = fork()) < 0) {
1142 sleep((unsigned)(i*i));
1143 continue;
1144 }
1145 /*
1146 * Child should run as daemon instead of root
1147 */
1148 if (pid == 0) {
1149 pw = getpwuid(DU);
1150 if (pw == 0) {
1151 syslog(LOG_ERR, "uid %ld not in password file",
1152 DU);
1153 break;
1154 }
1155 initgroups(pw->pw_name, pw->pw_gid);
1156 setgid(pw->pw_gid);
1157 setuid(DU);
1158 }
1159 return (pid);
1160 }
1161 syslog(LOG_ERR, "can't fork");
1162
1163 switch (action) {
1164 case DORETURN:
1165 return (-1);
1166 default:
1167 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1168 /*FALL THRU*/
1169 case DOABORT:
1170 exit(1);
1171 }
1172 /*NOTREACHED*/
1173 }
1174
1175 /*
1176 * Kill child processes to abort current job.
1177 */
1178 static void
1179 abortpr(signo)
1180 int signo;
1181 {
1182 (void)unlink(tempfile);
1183 kill(0, SIGINT);
1184 if (ofilter > 0)
1185 kill(ofilter, SIGCONT);
1186 while (wait(NULL) > 0)
1187 ;
1188 exit(0);
1189 }
1190
1191 static void
1192 init()
1193 {
1194 int status;
1195 char *s;
1196
1197 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1198 syslog(LOG_ERR, "can't open printer description file");
1199 exit(1);
1200 } else if (status == -1) {
1201 syslog(LOG_ERR, "unknown printer: %s", printer);
1202 exit(1);
1203 } else if (status == -3)
1204 fatal("potential reference loop detected in printcap file");
1205
1206 if (cgetstr(bp, "lp", &LP) == -1)
1207 LP = _PATH_DEFDEVLP;
1208 if (cgetstr(bp, "rp", &RP) == -1)
1209 RP = DEFLP;
1210 if (cgetstr(bp, "lo", &LO) == -1)
1211 LO = DEFLOCK;
1212 if (cgetstr(bp, "st", &ST) == -1)
1213 ST = DEFSTAT;
1214 if (cgetstr(bp, "lf", &LF) == -1)
1215 LF = _PATH_CONSOLE;
1216 if (cgetstr(bp, "sd", &SD) == -1)
1217 SD = _PATH_DEFSPOOL;
1218 if (cgetnum(bp, "du", &DU) < 0)
1219 DU = DEFUID;
1220 if (cgetstr(bp,"ff", &FF) == -1)
1221 FF = DEFFF;
1222 if (cgetnum(bp, "pw", &PW) < 0)
1223 PW = DEFWIDTH;
1224 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1225 if (cgetnum(bp, "pl", &PL) < 0)
1226 PL = DEFLENGTH;
1227 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1228 if (cgetnum(bp,"px", &PX) < 0)
1229 PX = 0;
1230 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1231 if (cgetnum(bp, "py", &PY) < 0)
1232 PY = 0;
1233 (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
1234 cgetstr(bp, "rm", &RM);
1235 if ((s = checkremote()) != NULL)
1236 syslog(LOG_WARNING, s);
1237
1238 cgetstr(bp, "af", &AF);
1239 cgetstr(bp, "of", &OF);
1240 cgetstr(bp, "if", &IF);
1241 cgetstr(bp, "rf", &RF);
1242 cgetstr(bp, "tf", &TF);
1243 cgetstr(bp, "nf", &NF);
1244 cgetstr(bp, "df", &DF);
1245 cgetstr(bp, "gf", &GF);
1246 cgetstr(bp, "vf", &VF);
1247 cgetstr(bp, "cf", &CF);
1248 cgetstr(bp, "tr", &TR);
1249
1250 RS = (cgetcap(bp, "rs", ':') != NULL);
1251 SF = (cgetcap(bp, "sf", ':') != NULL);
1252 SH = (cgetcap(bp, "sh", ':') != NULL);
1253 SB = (cgetcap(bp, "sb", ':') != NULL);
1254 HL = (cgetcap(bp, "hl", ':') != NULL);
1255 RW = (cgetcap(bp, "rw", ':') != NULL);
1256
1257 cgetnum(bp, "br", &BR);
1258 if (cgetnum(bp, "fc", &FC) < 0)
1259 FC = 0;
1260 if (cgetnum(bp, "fs", &FS) < 0)
1261 FS = 0;
1262 if (cgetnum(bp, "xc", &XC) < 0)
1263 XC = 0;
1264 if (cgetnum(bp, "xs", &XS) < 0)
1265 XS = 0;
1266 cgetstr(bp, "ms", &MS);
1267
1268 tof = (cgetcap(bp, "fo", ':') == NULL);
1269 }
1270
1271 /*
1272 * Acquire line printer or remote connection.
1273 */
1274 static void
1275 openpr()
1276 {
1277 int i, nofile;
1278 char *cp;
1279
1280 if (!remote && *LP) {
1281 if ((cp = strchr(LP, '@')))
1282 opennet(cp);
1283 else
1284 opentty();
1285 } else if (remote) {
1286 openrem();
1287 } else {
1288 syslog(LOG_ERR, "%s: no line printer device or host name",
1289 printer);
1290 exit(1);
1291 }
1292
1293 /*
1294 * Start up an output filter, if needed.
1295 */
1296 if (!remote && OF) {
1297 int p[2];
1298
1299 pipe(p);
1300 if ((ofilter = dofork(DOABORT)) == 0) { /* child */
1301 dup2(p[0], 0); /* pipe is std in */
1302 dup2(pfd, 1); /* printer is std out */
1303 closelog();
1304 nofile = sysconf(_SC_OPEN_MAX);
1305 for (i = 3; i < nofile; i++)
1306 (void)close(i);
1307 if ((cp = strrchr(OF, '/')) == NULL)
1308 cp = OF;
1309 else
1310 cp++;
1311 execl(OF, cp, width, length, 0);
1312 syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1313 exit(1);
1314 }
1315 (void)close(p[0]); /* close input side */
1316 ofd = p[1]; /* use pipe for output */
1317 } else {
1318 ofd = pfd;
1319 ofilter = 0;
1320 }
1321 }
1322
1323 /*
1324 * Printer connected directly to the network
1325 * or to a terminal server on the net
1326 */
1327 static void
1328 opennet(cp)
1329 char *cp;
1330 {
1331 int i;
1332 int resp, port;
1333 char save_ch;
1334
1335 save_ch = *cp;
1336 *cp = '\0';
1337 port = atoi(LP);
1338 if (port <= 0) {
1339 syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1340 exit(1);
1341 }
1342 *cp++ = save_ch;
1343
1344 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1345 resp = -1;
1346 pfd = getport(cp, port);
1347 if (pfd < 0 && errno == ECONNREFUSED)
1348 resp = 1;
1349 else if (pfd >= 0) {
1350 /*
1351 * need to delay a bit for rs232 lines
1352 * to stabilize in case printer is
1353 * connected via a terminal server
1354 */
1355 delay(500);
1356 break;
1357 }
1358 if (i == 1) {
1359 if (resp < 0)
1360 pstatus("waiting for %s to come up", LP);
1361 else
1362 pstatus("waiting for access to printer on %s", LP);
1363 }
1364 sleep(i);
1365 }
1366 pstatus("sending to %s port %d", cp, port);
1367 }
1368
1369 /*
1370 * Printer is connected to an RS232 port on this host
1371 */
1372 static void
1373 opentty()
1374 {
1375 int i;
1376
1377 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1378 pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1379 if (pfd >= 0) {
1380 delay(500);
1381 break;
1382 }
1383 if (errno == ENOENT) {
1384 syslog(LOG_ERR, "%s: %m", LP);
1385 exit(1);
1386 }
1387 if (i == 1)
1388 pstatus("waiting for %s to become ready (offline ?)",
1389 printer);
1390 sleep(i);
1391 }
1392 if (isatty(pfd))
1393 setty();
1394 pstatus("%s is ready and printing", printer);
1395 }
1396
1397 /*
1398 * Printer is on a remote host
1399 */
1400 static void
1401 openrem()
1402 {
1403 int i, n;
1404 int resp;
1405
1406 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1407 resp = -1;
1408 pfd = getport(RM, 0);
1409 if (pfd >= 0) {
1410 n = snprintf(line, sizeof(line), "\2%s\n", RP);
1411 if (write(pfd, line, n) == n &&
1412 (resp = response()) == '\0')
1413 break;
1414 (void) close(pfd);
1415 }
1416 if (i == 1) {
1417 if (resp < 0)
1418 pstatus("waiting for %s to come up", RM);
1419 else {
1420 pstatus("waiting for queue to be enabled on %s",
1421 RM);
1422 i = 256;
1423 }
1424 }
1425 sleep(i);
1426 }
1427 pstatus("sending to %s", RM);
1428 }
1429
1430 #if !defined(__NetBSD__)
1431 struct bauds {
1432 int baud;
1433 int speed;
1434 } bauds[] = {
1435 50, B50,
1436 75, B75,
1437 110, B110,
1438 134, B134,
1439 150, B150,
1440 200, B200,
1441 300, B300,
1442 600, B600,
1443 1200, B1200,
1444 1800, B1800,
1445 2400, B2400,
1446 4800, B4800,
1447 9600, B9600,
1448 19200, B19200,
1449 38400, B38400,
1450 57600, B57600,
1451 115200, B115200,
1452 0, 0
1453 };
1454 #endif
1455
1456 /*
1457 * setup tty lines.
1458 */
1459 static void
1460 setty()
1461 {
1462 struct info i;
1463 char **argv, **ap, *p, *val;
1464
1465 i.fd = pfd;
1466 i.set = i.wset = 0;
1467 if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
1468 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1469 exit(1);
1470 }
1471 if (tcgetattr(i.fd, &i.t) < 0) {
1472 syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1473 exit(1);
1474 }
1475 if (BR > 0) {
1476 #if !defined(__NetBSD__)
1477 struct bauds *bp;
1478 for (bp = bauds; bp->baud; bp++)
1479 if (BR == bp->baud)
1480 break;
1481 if (!bp->baud) {
1482 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1483 exit(1);
1484 }
1485 cfsetspeed(&i.t, bp->speed);
1486 #else
1487 cfsetspeed(&i.t, BR);
1488 #endif
1489 i.set = 1;
1490 }
1491 if (MS) {
1492 if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
1493 syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
1494 exit(1);
1495 }
1496 if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
1497 syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
1498 printer);
1499
1500 argv = (char **)calloc(256, sizeof(char *));
1501 if (argv == NULL) {
1502 syslog(LOG_ERR, "%s: calloc: %m", printer);
1503 exit(1);
1504 }
1505 p = strdup(MS);
1506 ap = argv;
1507 while ((val = strsep(&p, " \t,")) != NULL) {
1508 *ap++ = strdup(val);
1509 }
1510
1511 for (; *argv; ++argv) {
1512 if (ksearch(&argv, &i))
1513 continue;
1514 if (msearch(&argv, &i))
1515 continue;
1516 syslog(LOG_INFO, "%s: unknown stty flag: %s",
1517 printer, *argv);
1518 }
1519 } else {
1520 if (FC) {
1521 sttyclearflags(&i.t, FC);
1522 i.set = 1;
1523 }
1524 if (FS) {
1525 sttysetflags(&i.t, FS);
1526 i.set = 1;
1527 }
1528 if (XC) {
1529 sttyclearlflags(&i.t, XC);
1530 i.set = 1;
1531 }
1532 if (XS) {
1533 sttysetlflags(&i.t, XS);
1534 i.set = 1;
1535 }
1536 }
1537
1538 if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
1539 syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1540 exit(1);
1541 }
1542 if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
1543 syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
1544 return;
1545 }
1546
1547 #ifdef __STDC__
1548 #include <stdarg.h>
1549 #else
1550 #include <varargs.h>
1551 #endif
1552
1553 static void
1554 #ifdef __STDC__
1555 pstatus(const char *msg, ...)
1556 #else
1557 pstatus(msg, va_alist)
1558 char *msg;
1559 va_dcl
1560 #endif
1561 {
1562 int fd;
1563 char buf[BUFSIZ];
1564 va_list ap;
1565 #ifdef __STDC__
1566 va_start(ap, msg);
1567 #else
1568 va_start(ap);
1569 #endif
1570
1571 umask(0);
1572 fd = open(ST, O_WRONLY|O_CREAT, 0664);
1573 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1574 syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1575 exit(1);
1576 }
1577 ftruncate(fd, 0);
1578 (void)vsnprintf(buf, sizeof(buf) - 2, msg, ap);
1579 va_end(ap);
1580 strncat(buf, "\n", 2);
1581 (void)write(fd, buf, strlen(buf));
1582 (void)close(fd);
1583 }
1584