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