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