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