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

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