source: trunk/athena/bin/lpr/printjob.c @ 8138

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