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