home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / lpr / lpd / printjob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  29.3 KB  |  1,292 lines

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