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