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