printjob.c revision 68734
155682Smarkm/* 278527Sassar * Copyright (c) 1983, 1993 355682Smarkm * The Regents of the University of California. All rights reserved. 455682Smarkm * 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1. Redistributions of source code must retain the above copyright 1055682Smarkm * notice, this list of conditions and the following disclaimer. 1155682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1255682Smarkm * notice, this list of conditions and the following disclaimer in the 1355682Smarkm * documentation and/or other materials provided with the distribution. 1455682Smarkm * 3. All advertising materials mentioning features or use of this software 1555682Smarkm * must display the following acknowledgement: 1655682Smarkm * This product includes software developed by the University of 1755682Smarkm * California, Berkeley and its contributors. 1855682Smarkm * 4. Neither the name of the University nor the names of its contributors 1955682Smarkm * may be used to endorse or promote products derived from this software 2055682Smarkm * without specific prior written permission. 2155682Smarkm * 2255682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2355682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2455682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2555682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2655682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2755682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2855682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2955682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3055682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3155682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3255682Smarkm * SUCH DAMAGE. 3355682Smarkm */ 3455682Smarkm 3555682Smarkm#ifndef lint 3678527Sassarstatic const char copyright[] = 3755682Smarkm"@(#) Copyright (c) 1983, 1993\n\ 3872445Sassar The Regents of the University of California. All rights reserved.\n"; 3972445Sassar#endif /* not lint */ 4055682Smarkm 4155682Smarkm#ifndef lint 4255682Smarkm/* 4355682Smarkmstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 4455682Smarkm*/ 4555682Smarkmstatic const char rcsid[] = 4655682Smarkm "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 68734 2000-11-14 22:03:59Z gad $"; 4755682Smarkm#endif /* not lint */ 4855682Smarkm 4955682Smarkm 5055682Smarkm/* 5172445Sassar * printjob -- print jobs in the queue. 5255682Smarkm * 5355682Smarkm * NOTE: the lock file is used to pass information to lpq and lprm. 5455682Smarkm * it does not need to be removed because file locks are dynamic. 5555682Smarkm */ 5655682Smarkm 5755682Smarkm#include <sys/param.h> 5855682Smarkm#include <sys/wait.h> 5955682Smarkm#include <sys/stat.h> 6055682Smarkm#include <sys/types.h> 6155682Smarkm 6255682Smarkm#include <pwd.h> 6355682Smarkm#include <unistd.h> 6455682Smarkm#include <signal.h> 6555682Smarkm#include <syslog.h> 6655682Smarkm#include <fcntl.h> 6755682Smarkm#include <dirent.h> 6855682Smarkm#include <errno.h> 6955682Smarkm#include <stdio.h> 7055682Smarkm#include <string.h> 7172445Sassar#include <stdlib.h> 7272445Sassar#include <sys/ioctl.h> 7355682Smarkm#include <termios.h> 7455682Smarkm#include <time.h> 7555682Smarkm#include "lp.h" 7655682Smarkm#include "lp.local.h" 7755682Smarkm#include "pathnames.h" 7855682Smarkm#include "extern.h" 7955682Smarkm 8055682Smarkm#define DORETURN 0 /* absorb fork error */ 8155682Smarkm#define DOABORT 1 /* abort if dofork fails */ 8255682Smarkm 8355682Smarkm/* 8455682Smarkm * Error tokens 8555682Smarkm */ 8655682Smarkm#define REPRINT -2 8755682Smarkm#define ERROR -1 8855682Smarkm#define OK 0 8955682Smarkm#define FATALERR 1 9055682Smarkm#define NOACCT 2 9155682Smarkm#define FILTERERR 3 9255682Smarkm#define ACCESS 4 9355682Smarkm 9455682Smarkmstatic dev_t fdev; /* device of file pointed to by symlink */ 9555682Smarkmstatic ino_t fino; /* inode of file pointed to by symlink */ 9655682Smarkmstatic FILE *cfp; /* control file */ 9755682Smarkmstatic int child; /* id of any filters */ 9855682Smarkmstatic int job_dfcnt; /* count of datafiles in current user job */ 9955682Smarkmstatic int lfd; /* lock file descriptor */ 10055682Smarkmstatic int ofd; /* output filter file descriptor */ 10155682Smarkmstatic int ofilter; /* id of output filter, if any */ 10255682Smarkmstatic int tfd = -1; /* output filter temp file output */ 10355682Smarkmstatic int pfd; /* prstatic inter file descriptor */ 10455682Smarkmstatic int pid; /* pid of lpd process */ 10555682Smarkmstatic int prchild; /* id of pr process */ 10655682Smarkmstatic char title[80]; /* ``pr'' title */ 10755682Smarkmstatic char locale[80]; /* ``pr'' locale */ 10855682Smarkm 10955682Smarkmstatic char class[32]; /* classification field */ 11055682Smarkmstatic char fromhost[MAXHOSTNAMELEN]; /* user's host machine */ 11155682Smarkm /* indentation size in static characters */ 11255682Smarkmstatic char indent[10] = "-i0"; 11355682Smarkmstatic char jobname[100]; /* job or file name */ 11472445Sassarstatic char length[10] = "-l"; /* page length in lines */ 11555682Smarkmstatic char logname[32]; /* user's login name */ 11655682Smarkmstatic char pxlength[10] = "-y"; /* page length in pixels */ 11755682Smarkmstatic char pxwidth[10] = "-x"; /* page width in pixels */ 11855682Smarkm/* tempstderr is the filename used to catch stderr from exec-ing filters */ 11972445Sassarstatic char tempstderr[] = "errs.XXXXXXX"; 12055682Smarkmstatic char width[10] = "-w"; /* page width in static characters */ 12155682Smarkm#define TFILENAME "fltXXXXXX" 12255682Smarkmstatic char tfile[] = TFILENAME; /* file name for filter output */ 12355682Smarkm 12455682Smarkmstatic void abortpr __P((int)); 12555682Smarkmstatic void alarmhandler __P((int)); 12655682Smarkmstatic void banner __P((struct printer *pp, char *name1, char *name2)); 12755682Smarkmstatic int dofork __P((const struct printer *pp, int action)); 12855682Smarkmstatic int dropit __P((int)); 12955682Smarkmstatic void init __P((struct printer *pp)); 13055682Smarkmstatic void openpr __P((const struct printer *pp)); 13155682Smarkmstatic void opennet __P((const struct printer *pp)); 13255682Smarkmstatic void opentty __P((const struct printer *pp)); 13355682Smarkmstatic void openrem __P((const struct printer *pp)); 13455682Smarkmstatic int print __P((struct printer *pp, int format, char *file)); 13555682Smarkmstatic int printit __P((struct printer *pp, char *file)); 13655682Smarkmstatic void pstatus __P((const struct printer *, const char *, ...)); 13755682Smarkmstatic char response __P((const struct printer *pp)); 13855682Smarkmstatic void scan_out __P((struct printer *pp, int scfd, char *scsp, 13955682Smarkm int dlm)); 14055682Smarkmstatic char *scnline __P((int, char *, int)); 14155682Smarkmstatic int sendfile __P((struct printer *pp, int type, char *file, 14255682Smarkm int format)); 14355682Smarkmstatic int sendit __P((struct printer *pp, char *file)); 14455682Smarkmstatic void sendmail __P((struct printer *pp, char *user, int bombed)); 14555682Smarkmstatic void setty __P((const struct printer *pp)); 14672445Sassar 14755682Smarkmvoid 14855682Smarkmprintjob(pp) 14955682Smarkm struct printer *pp; 15055682Smarkm{ 15155682Smarkm struct stat stb; 15255682Smarkm register struct jobqueue *q, **qp; 15355682Smarkm struct jobqueue **queue; 15455682Smarkm register int i, nitems; 15555682Smarkm off_t pidoff; 15655682Smarkm int errcnt, jobcount, tempfd; 15755682Smarkm 15855682Smarkm jobcount = 0; 15955682Smarkm init(pp); /* set up capabilities */ 16055682Smarkm (void) write(1, "", 1); /* ack that daemon is started */ 16155682Smarkm (void) close(2); /* set up log file */ 16272445Sassar if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 16355682Smarkm syslog(LOG_ERR, "%s: %m", pp->log_file); 16455682Smarkm (void) open(_PATH_DEVNULL, O_WRONLY); 16555682Smarkm } 16655682Smarkm setgid(getegid()); 16755682Smarkm pid = getpid(); /* for use with lprm */ 16855682Smarkm setpgrp(0, pid); 16955682Smarkm signal(SIGHUP, abortpr); 17055682Smarkm signal(SIGINT, abortpr); 17155682Smarkm signal(SIGQUIT, abortpr); 17255682Smarkm signal(SIGTERM, abortpr); 17355682Smarkm 17455682Smarkm /* 17555682Smarkm * uses short form file names 17655682Smarkm */ 17755682Smarkm if (chdir(pp->spool_dir) < 0) { 17855682Smarkm syslog(LOG_ERR, "%s: %m", pp->spool_dir); 17955682Smarkm exit(1); 18055682Smarkm } 18155682Smarkm if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 18255682Smarkm exit(0); /* printing disabled */ 18355682Smarkm lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 18455682Smarkm LOCK_FILE_MODE); 18555682Smarkm if (lfd < 0) { 18655682Smarkm if (errno == EWOULDBLOCK) /* active daemon present */ 18755682Smarkm exit(0); 18855682Smarkm syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 18955682Smarkm exit(1); 19055682Smarkm } 19155682Smarkm /* turn off non-blocking mode (was turned on for lock effects only) */ 19255682Smarkm if (fcntl(lfd, F_SETFL, 0) < 0) { 19355682Smarkm syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 19455682Smarkm exit(1); 19555682Smarkm } 19672445Sassar ftruncate(lfd, 0); 19772445Sassar /* 19872445Sassar * write process id for others to know 19972445Sassar */ 20072445Sassar sprintf(line, "%u\n", pid); 20155682Smarkm pidoff = i = strlen(line); 20272445Sassar if (write(lfd, line, i) != i) { 20355682Smarkm syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 20472445Sassar exit(1); 20572445Sassar } 20672445Sassar /* 20772445Sassar * search the spool directory for work and sort by queue order. 20872445Sassar */ 20972445Sassar if ((nitems = getq(pp, &queue)) < 0) { 21072445Sassar syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 21172445Sassar pp->spool_dir); 21272445Sassar exit(1); 21372445Sassar } 21472445Sassar if (nitems == 0) /* no work to do */ 21572445Sassar exit(0); 21672445Sassar if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 21772445Sassar if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 21872445Sassar syslog(LOG_ERR, "%s: %s: %m", pp->printer, 21972445Sassar pp->lock_file); 22072445Sassar } 22172445Sassar 22255682Smarkm /* create a file which will be used to hold stderr from filters */ 22355682Smarkm if ((tempfd = mkstemp(tempstderr)) == -1) { 22455682Smarkm syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 22572445Sassar tempstderr); 22672445Sassar exit(1); 22772445Sassar } 22872445Sassar if ((i = fchmod(tempfd, 0664)) == -1) { 22972445Sassar syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 23072445Sassar tempstderr); 23172445Sassar exit(1); 23272445Sassar } 23372445Sassar /* lpd doesn't need it to be open, it just needs it to exist */ 23472445Sassar close(tempfd); 23572445Sassar 23672445Sassar openpr(pp); /* open printer or remote */ 23772445Sassaragain: 23872445Sassar /* 23972445Sassar * we found something to do now do it -- 24072445Sassar * write the name of the current control file into the lock file 24172445Sassar * so the spool queue program can tell what we're working on 24272445Sassar */ 24372445Sassar for (qp = queue; nitems--; free((char *) q)) { 24472445Sassar q = *qp++; 24572445Sassar if (stat(q->job_cfname, &stb) < 0) 24672445Sassar continue; 24772445Sassar errcnt = 0; 24872445Sassar restart: 24972445Sassar (void) lseek(lfd, pidoff, 0); 25072445Sassar (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 25172445Sassar i = strlen(line); 25272445Sassar if (write(lfd, line, i) != i) 25372445Sassar syslog(LOG_ERR, "%s: %s: %m", pp->printer, 25472445Sassar pp->lock_file); 25572445Sassar if (!pp->remote) 25672445Sassar i = printit(pp, q->job_cfname); 25772445Sassar else 25872445Sassar i = sendit(pp, q->job_cfname); 25972445Sassar /* 26072445Sassar * Check to see if we are supposed to stop printing or 26172445Sassar * if we are to rebuild the queue. 26272445Sassar */ 26372445Sassar if (fstat(lfd, &stb) == 0) { 26472445Sassar /* stop printing before starting next job? */ 26572445Sassar if (stb.st_mode & LFM_PRINT_DIS) 26672445Sassar goto done; 26755682Smarkm /* rebuild queue (after lpc topq) */ 26872445Sassar if (stb.st_mode & LFM_RESET_QUE) { 26955682Smarkm for (free(q); nitems--; free(q)) 27072445Sassar q = *qp++; 27155682Smarkm if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 27255682Smarkm < 0) 27355682Smarkm syslog(LOG_WARNING, "%s: %s: %m", 27455682Smarkm pp->printer, pp->lock_file); 27555682Smarkm break; 27655682Smarkm } 27755682Smarkm } 27855682Smarkm if (i == OK) /* all files of this job printed */ 27955682Smarkm jobcount++; 28055682Smarkm else if (i == REPRINT && ++errcnt < 5) { 28155682Smarkm /* try reprinting the job */ 28255682Smarkm syslog(LOG_INFO, "restarting %s", pp->printer); 28355682Smarkm if (ofilter > 0) { 28455682Smarkm kill(ofilter, SIGCONT); /* to be sure */ 28555682Smarkm (void) close(ofd); 28655682Smarkm while ((i = wait(NULL)) > 0 && i != ofilter) 28755682Smarkm ; 28855682Smarkm ofilter = 0; 28955682Smarkm } 29055682Smarkm (void) close(pfd); /* close printer */ 29155682Smarkm if (ftruncate(lfd, pidoff) < 0) 29255682Smarkm syslog(LOG_WARNING, "%s: %s: %m", 29372445Sassar pp->printer, pp->lock_file); 29455682Smarkm openpr(pp); /* try to reopen printer */ 29555682Smarkm goto restart; 29655682Smarkm } else { 29755682Smarkm syslog(LOG_WARNING, "%s: job could not be %s (%s)", 29855682Smarkm pp->printer, 29955682Smarkm pp->remote ? "sent to remote host" : "printed", 30055682Smarkm q->job_cfname); 30172445Sassar if (i == REPRINT) { 30255682Smarkm /* ensure we don't attempt this job again */ 30355682Smarkm (void) unlink(q->job_cfname); 30472445Sassar q->job_cfname[0] = 'd'; 30555682Smarkm (void) unlink(q->job_cfname); 30655682Smarkm if (logname[0]) 30755682Smarkm sendmail(pp, logname, FATALERR); 30855682Smarkm } 30955682Smarkm } 31055682Smarkm } 31155682Smarkm free(queue); 31272445Sassar /* 31355682Smarkm * search the spool directory for more work. 31455682Smarkm */ 31572445Sassar if ((nitems = getq(pp, &queue)) < 0) { 31655682Smarkm syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 31755682Smarkm pp->spool_dir); 31855682Smarkm exit(1); 31972445Sassar } 32072445Sassar if (nitems == 0) { /* no more work to do */ 32172445Sassar done: 32255682Smarkm if (jobcount > 0) { /* jobs actually printed */ 32355682Smarkm if (!pp->no_formfeed && !pp->tof) 32455682Smarkm (void) write(ofd, pp->form_feed, 32555682Smarkm strlen(pp->form_feed)); 32655682Smarkm if (pp->trailer != NULL) /* output trailer */ 32755682Smarkm (void) write(ofd, pp->trailer, 32855682Smarkm strlen(pp->trailer)); 32955682Smarkm } 33055682Smarkm (void) close(ofd); 33172445Sassar (void) wait(NULL); 33255682Smarkm (void) unlink(tempstderr); 33355682Smarkm exit(0); 33455682Smarkm } 33555682Smarkm goto again; 33655682Smarkm} 33755682Smarkm 33855682Smarkmchar fonts[4][50]; /* fonts for troff */ 33955682Smarkm 34055682Smarkmchar ifonts[4][40] = { 34155682Smarkm _PATH_VFONTR, 34255682Smarkm _PATH_VFONTI, 34372445Sassar _PATH_VFONTB, 34472445Sassar _PATH_VFONTS, 34572445Sassar}; 34672445Sassar 34772445Sassar/* 34872445Sassar * The remaining part is the reading of the control file (cf) 34972445Sassar * and performing the various actions. 35055682Smarkm */ 35172445Sassarstatic int 35272445Sassarprintit(pp, file) 35372445Sassar struct printer *pp; 35455682Smarkm char *file; 35555682Smarkm{ 35655682Smarkm register int i; 35772445Sassar char *cp; 35855682Smarkm int bombed, didignorehdr; 35955682Smarkm 36055682Smarkm bombed = OK; 36155682Smarkm didignorehdr = 0; 36255682Smarkm /* 36355682Smarkm * open control file; ignore if no longer there. 36455682Smarkm */ 36555682Smarkm if ((cfp = fopen(file, "r")) == NULL) { 36655682Smarkm syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 36755682Smarkm return(OK); 36855682Smarkm } 36955682Smarkm /* 37055682Smarkm * Reset troff fonts. 37172445Sassar */ 37255682Smarkm for (i = 0; i < 4; i++) 37355682Smarkm strcpy(fonts[i], ifonts[i]); 37455682Smarkm sprintf(&width[2], "%ld", pp->page_width); 37555682Smarkm strcpy(indent+2, "0"); 37655682Smarkm 37755682Smarkm /* initialize job-specific count of datafiles processed */ 37855682Smarkm job_dfcnt = 0; 37955682Smarkm 38055682Smarkm /* 38155682Smarkm * read the control file for work to do 38255682Smarkm * 38372445Sassar * file format -- first character in the line is a command 38472445Sassar * rest of the line is the argument. 38572445Sassar * valid commands are: 38672445Sassar * 38772445Sassar * S -- "stat info" for symbolic link protection 38872445Sassar * J -- "job name" on banner page 38972445Sassar * C -- "class name" on banner page 39072445Sassar * L -- "literal" user's name to print on banner 39172445Sassar * T -- "title" for pr 39272445Sassar * H -- "host name" of machine where lpr was done 39372445Sassar * P -- "person" user's login name 39455682Smarkm * I -- "indent" amount to indent output 39555682Smarkm * R -- laser dpi "resolution" 39655682Smarkm * f -- "file name" name of text file to print 39755682Smarkm * l -- "file name" text file with control chars 39855682Smarkm * p -- "file name" text file to print with pr(1) 39972445Sassar * t -- "file name" troff(1) file to print 40072445Sassar * n -- "file name" ditroff(1) file to print 40172445Sassar * d -- "file name" dvi file to print 40272445Sassar * g -- "file name" plot(1G) file to print 40372445Sassar * v -- "file name" plain raster file to print 40472445Sassar * c -- "file name" cifplot file to print 40555682Smarkm * 1 -- "R font file" for troff 40655682Smarkm * 2 -- "I font file" for troff 40755682Smarkm * 3 -- "B font file" for troff 40855682Smarkm * 4 -- "S font file" for troff 40955682Smarkm * N -- "name" of file (used by lpq) 41055682Smarkm * U -- "unlink" name of file to remove 41155682Smarkm * (after we print it. (Pass 2 only)). 41255682Smarkm * M -- "mail" to user when done printing 41355682Smarkm * Z -- "locale" for pr 41455682Smarkm * 41555682Smarkm * getline reads a line and expands tabs to blanks 41655682Smarkm */ 41755682Smarkm 41872445Sassar /* pass 1 */ 41972445Sassar 42055682Smarkm while (getline(cfp)) 42155682Smarkm switch (line[0]) { 42255682Smarkm case 'H': 42355682Smarkm strncpy(fromhost, line+1, sizeof(fromhost) - 1); 42455682Smarkm fromhost[sizeof(fromhost) - 1] = '\0'; 42555682Smarkm if (class[0] == '\0') { 42655682Smarkm strncpy(class, line+1, sizeof(class) - 1); 42772445Sassar class[sizeof(class) - 1] = '\0'; 42872445Sassar } 42972445Sassar continue; 43055682Smarkm 43155682Smarkm case 'P': 43255682Smarkm strncpy(logname, line+1, sizeof(logname) - 1); 43355682Smarkm logname[sizeof(logname) - 1] = '\0'; 43455682Smarkm if (pp->restricted) { /* restricted */ 43555682Smarkm if (getpwnam(logname) == NULL) { 43655682Smarkm bombed = NOACCT; 43755682Smarkm sendmail(pp, line+1, bombed); 43855682Smarkm goto pass2; 43955682Smarkm } 44055682Smarkm } 44155682Smarkm continue; 44255682Smarkm 44355682Smarkm case 'S': 44455682Smarkm cp = line+1; 44555682Smarkm i = 0; 44655682Smarkm while (*cp >= '0' && *cp <= '9') 44755682Smarkm i = i * 10 + (*cp++ - '0'); 44855682Smarkm fdev = i; 44955682Smarkm cp++; 45055682Smarkm i = 0; 45155682Smarkm while (*cp >= '0' && *cp <= '9') 45272445Sassar i = i * 10 + (*cp++ - '0'); 45355682Smarkm fino = i; 45455682Smarkm continue; 45555682Smarkm 45672445Sassar case 'J': 45755682Smarkm if (line[1] != '\0') { 45855682Smarkm strncpy(jobname, line+1, sizeof(jobname) - 1); 45955682Smarkm jobname[sizeof(jobname) - 1] = '\0'; 46055682Smarkm } else 46172445Sassar strcpy(jobname, " "); 46255682Smarkm continue; 46355682Smarkm 46455682Smarkm case 'C': 46555682Smarkm if (line[1] != '\0') 46655682Smarkm strncpy(class, line+1, sizeof(class) - 1); 46755682Smarkm else if (class[0] == '\0') 46855682Smarkm gethostname(class, sizeof(class)); 46955682Smarkm class[sizeof(class) - 1] = '\0'; 47072445Sassar continue; 47155682Smarkm 47272445Sassar case 'T': /* header title for pr */ 47355682Smarkm strncpy(title, line+1, sizeof(title) - 1); 47455682Smarkm title[sizeof(title) - 1] = '\0'; 47578527Sassar continue; 47655682Smarkm 47778527Sassar case 'L': /* identification line */ 47872445Sassar if (!pp->no_header && !pp->header_last) 47955682Smarkm banner(pp, line+1, jobname); 48055682Smarkm continue; 48155682Smarkm 48255682Smarkm case '1': /* troff fonts */ 48372445Sassar case '2': 48455682Smarkm case '3': 48555682Smarkm case '4': 48655682Smarkm if (line[1] != '\0') { 48755682Smarkm strncpy(fonts[line[0]-'1'], line+1, 48855682Smarkm 50-1); 48955682Smarkm fonts[line[0]-'1'][50-1] = '\0'; 49055682Smarkm } 491 continue; 492 493 case 'W': /* page width */ 494 strncpy(width+2, line+1, sizeof(width) - 3); 495 width[2+sizeof(width) - 3] = '\0'; 496 continue; 497 498 case 'I': /* indent amount */ 499 strncpy(indent+2, line+1, sizeof(indent) - 3); 500 indent[2+sizeof(indent) - 3] = '\0'; 501 continue; 502 503 case 'Z': /* locale for pr */ 504 strncpy(locale, line+1, sizeof(locale) - 1); 505 locale[sizeof(locale) - 1] = '\0'; 506 continue; 507 508 default: /* some file to print */ 509 /* only lowercase cmd-codes include a file-to-print */ 510 if ((line[0] < 'a') || (line[0] > 'z')) { 511 /* ignore any other lines */ 512 if (lflag <= 1) 513 continue; 514 if (!didignorehdr) { 515 syslog(LOG_INFO, "%s: in %s :", 516 pp->printer, file); 517 didignorehdr = 1; 518 } 519 syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 520 pp->printer, line[0], &line[1]); 521 continue; 522 } 523 i = print(pp, line[0], line+1); 524 switch (i) { 525 case ERROR: 526 if (bombed == OK) 527 bombed = FATALERR; 528 break; 529 case REPRINT: 530 (void) fclose(cfp); 531 return(REPRINT); 532 case FILTERERR: 533 case ACCESS: 534 bombed = i; 535 sendmail(pp, logname, bombed); 536 } 537 title[0] = '\0'; 538 continue; 539 540 case 'N': 541 case 'U': 542 case 'M': 543 case 'R': 544 continue; 545 } 546 547 /* pass 2 */ 548 549pass2: 550 fseek(cfp, 0L, 0); 551 while (getline(cfp)) 552 switch (line[0]) { 553 case 'L': /* identification line */ 554 if (!pp->no_header && pp->header_last) 555 banner(pp, line+1, jobname); 556 continue; 557 558 case 'M': 559 if (bombed < NOACCT) /* already sent if >= NOACCT */ 560 sendmail(pp, line+1, bombed); 561 continue; 562 563 case 'U': 564 if (strchr(line+1, '/')) 565 continue; 566 (void) unlink(line+1); 567 } 568 /* 569 * clean-up in case another control file exists 570 */ 571 (void) fclose(cfp); 572 (void) unlink(file); 573 return(bombed == OK ? OK : ERROR); 574} 575 576/* 577 * Print a file. 578 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 579 * Return -1 if a non-recoverable error occured, 580 * 2 if the filter detected some errors (but printed the job anyway), 581 * 1 if we should try to reprint this job and 582 * 0 if all is well. 583 * Note: all filters take stdin as the file, stdout as the printer, 584 * stderr as the log file, and must not ignore SIGINT. 585 */ 586static int 587print(pp, format, file) 588 struct printer *pp; 589 int format; 590 char *file; 591{ 592 register int n, i; 593 register char *prog; 594 int fi, fo; 595 FILE *fp; 596 char *av[15], buf[BUFSIZ]; 597 int pid, p[2], stopped; 598 union wait status; 599 struct stat stb; 600 601 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 602 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 603 pp->printer, file, format); 604 return(ERROR); 605 } 606 /* 607 * Check to see if data file is a symbolic link. If so, it should 608 * still point to the same file or someone is trying to print 609 * something he shouldn't. 610 */ 611 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 612 (stb.st_dev != fdev || stb.st_ino != fino)) 613 return(ACCESS); 614 615 job_dfcnt++; /* increment datafile counter for this job */ 616 stopped = 0; /* output filter is not stopped */ 617 618 /* everything seems OK, start it up */ 619 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 620 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 621 pp->tof = 1; 622 } 623 if (pp->filters[LPF_INPUT] == NULL 624 && (format == 'f' || format == 'l')) { 625 pp->tof = 0; 626 while ((n = read(fi, buf, BUFSIZ)) > 0) 627 if (write(ofd, buf, n) != n) { 628 (void) close(fi); 629 return(REPRINT); 630 } 631 (void) close(fi); 632 return(OK); 633 } 634 switch (format) { 635 case 'p': /* print file using 'pr' */ 636 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 637 prog = _PATH_PR; 638 i = 0; 639 av[i++] = "pr"; 640 av[i++] = width; 641 av[i++] = length; 642 av[i++] = "-h"; 643 av[i++] = *title ? title : " "; 644 av[i++] = "-L"; 645 av[i++] = *locale ? locale : "C"; 646 av[i++] = "-F"; 647 av[i] = 0; 648 fo = ofd; 649 goto start; 650 } 651 pipe(p); 652 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 653 dup2(fi, 0); /* file is stdin */ 654 dup2(p[1], 1); /* pipe is stdout */ 655 closelog(); 656 closeallfds(3); 657 execl(_PATH_PR, "pr", width, length, 658 "-h", *title ? title : " ", 659 "-L", *locale ? locale : "C", 660 "-F", 0); 661 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 662 exit(2); 663 } 664 (void) close(p[1]); /* close output side */ 665 (void) close(fi); 666 if (prchild < 0) { 667 prchild = 0; 668 (void) close(p[0]); 669 return(ERROR); 670 } 671 fi = p[0]; /* use pipe for input */ 672 case 'f': /* print plain text file */ 673 prog = pp->filters[LPF_INPUT]; 674 av[1] = width; 675 av[2] = length; 676 av[3] = indent; 677 n = 4; 678 break; 679 case 'l': /* like 'f' but pass control characters */ 680 prog = pp->filters[LPF_INPUT]; 681 av[1] = "-c"; 682 av[2] = width; 683 av[3] = length; 684 av[4] = indent; 685 n = 5; 686 break; 687 case 'r': /* print a fortran text file */ 688 prog = pp->filters[LPF_FORTRAN]; 689 av[1] = width; 690 av[2] = length; 691 n = 3; 692 break; 693 case 't': /* print troff output */ 694 case 'n': /* print ditroff output */ 695 case 'd': /* print tex output */ 696 (void) unlink(".railmag"); 697 if ((fo = creat(".railmag", FILMOD)) < 0) { 698 syslog(LOG_ERR, "%s: cannot create .railmag", 699 pp->printer); 700 (void) unlink(".railmag"); 701 } else { 702 for (n = 0; n < 4; n++) { 703 if (fonts[n][0] != '/') 704 (void) write(fo, _PATH_VFONT, 705 sizeof(_PATH_VFONT) - 1); 706 (void) write(fo, fonts[n], strlen(fonts[n])); 707 (void) write(fo, "\n", 1); 708 } 709 (void) close(fo); 710 } 711 prog = (format == 't') ? pp->filters[LPF_TROFF] 712 : ((format == 'n') ? pp->filters[LPF_DITROFF] 713 : pp->filters[LPF_DVI]); 714 av[1] = pxwidth; 715 av[2] = pxlength; 716 n = 3; 717 break; 718 case 'c': /* print cifplot output */ 719 prog = pp->filters[LPF_CIFPLOT]; 720 av[1] = pxwidth; 721 av[2] = pxlength; 722 n = 3; 723 break; 724 case 'g': /* print plot(1G) output */ 725 prog = pp->filters[LPF_GRAPH]; 726 av[1] = pxwidth; 727 av[2] = pxlength; 728 n = 3; 729 break; 730 case 'v': /* print raster output */ 731 prog = pp->filters[LPF_RASTER]; 732 av[1] = pxwidth; 733 av[2] = pxlength; 734 n = 3; 735 break; 736 default: 737 (void) close(fi); 738 syslog(LOG_ERR, "%s: illegal format character '%c'", 739 pp->printer, format); 740 return(ERROR); 741 } 742 if (prog == NULL) { 743 (void) close(fi); 744 syslog(LOG_ERR, 745 "%s: no filter found in printcap for format character '%c'", 746 pp->printer, format); 747 return(ERROR); 748 } 749 if ((av[0] = strrchr(prog, '/')) != NULL) 750 av[0]++; 751 else 752 av[0] = prog; 753 av[n++] = "-n"; 754 av[n++] = logname; 755 av[n++] = "-h"; 756 av[n++] = fromhost; 757 av[n++] = pp->acct_file; 758 av[n] = 0; 759 fo = pfd; 760 if (ofilter > 0) { /* stop output filter */ 761 write(ofd, "\031\1", 2); 762 while ((pid = 763 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 764 ; 765 if (status.w_stopval != WSTOPPED) { 766 (void) close(fi); 767 syslog(LOG_WARNING, 768 "%s: output filter died " 769 "(retcode=%d termsig=%d)", 770 pp->printer, status.w_retcode, 771 status.w_termsig); 772 return(REPRINT); 773 } 774 stopped++; 775 } 776start: 777 if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 778 dup2(fi, 0); 779 dup2(fo, 1); 780 /* setup stderr for the filter (child process) 781 * so it goes to our temporary errors file */ 782 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 783 if (n >= 0) 784 dup2(n, 2); 785 closelog(); 786 closeallfds(3); 787 execv(prog, av); 788 syslog(LOG_ERR, "cannot execv %s", prog); 789 exit(2); 790 } 791 (void) close(fi); 792 if (child < 0) 793 status.w_retcode = 100; 794 else 795 while ((pid = wait((int *)&status)) > 0 && pid != child) 796 ; 797 child = 0; 798 prchild = 0; 799 if (stopped) { /* restart output filter */ 800 if (kill(ofilter, SIGCONT) < 0) { 801 syslog(LOG_ERR, "cannot restart output filter"); 802 exit(1); 803 } 804 } 805 pp->tof = 0; 806 807 /* Copy the filter's output to "lf" logfile */ 808 if ((fp = fopen(tempstderr, "r"))) { 809 while (fgets(buf, sizeof(buf), fp)) 810 fputs(buf, stderr); 811 fclose(fp); 812 } 813 814 if (!WIFEXITED(status)) { 815 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 816 pp->printer, format, status.w_termsig); 817 return(ERROR); 818 } 819 switch (status.w_retcode) { 820 case 0: 821 pp->tof = 1; 822 return(OK); 823 case 1: 824 return(REPRINT); 825 case 2: 826 return(ERROR); 827 default: 828 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 829 pp->printer, format, status.w_retcode); 830 return(FILTERERR); 831 } 832} 833 834/* 835 * Send the daemon control file (cf) and any data files. 836 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 837 * 0 if all is well. 838 */ 839static int 840sendit(pp, file) 841 struct printer *pp; 842 char *file; 843{ 844 register int i, err = OK; 845 char *cp, last[BUFSIZ]; 846 847 /* 848 * open control file 849 */ 850 if ((cfp = fopen(file, "r")) == NULL) 851 return(OK); 852 853 /* initialize job-specific count of datafiles processed */ 854 job_dfcnt = 0; 855 856 /* 857 * read the control file for work to do 858 * 859 * file format -- first character in the line is a command 860 * rest of the line is the argument. 861 * commands of interest are: 862 * 863 * a-z -- "file name" name of file to print 864 * U -- "unlink" name of file to remove 865 * (after we print it. (Pass 2 only)). 866 */ 867 868 /* 869 * pass 1 870 */ 871 while (getline(cfp)) { 872 again: 873 if (line[0] == 'S') { 874 cp = line+1; 875 i = 0; 876 while (*cp >= '0' && *cp <= '9') 877 i = i * 10 + (*cp++ - '0'); 878 fdev = i; 879 cp++; 880 i = 0; 881 while (*cp >= '0' && *cp <= '9') 882 i = i * 10 + (*cp++ - '0'); 883 fino = i; 884 } else if (line[0] == 'H') { 885 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 886 fromhost[sizeof(fromhost) - 1] = '\0'; 887 if (class[0] == '\0') { 888 strncpy(class, line+1, sizeof(class) - 1); 889 class[sizeof(class) - 1] = '\0'; 890 } 891 } else if (line[0] == 'P') { 892 strncpy(logname, line+1, sizeof(logname) - 1); 893 if (pp->restricted) { /* restricted */ 894 if (getpwnam(logname) == NULL) { 895 sendmail(pp, line+1, NOACCT); 896 err = ERROR; 897 break; 898 } 899 } 900 } else if (line[0] == 'I') { 901 strncpy(indent+2, line+1, sizeof(indent) - 3); 902 } else if (line[0] >= 'a' && line[0] <= 'z') { 903 strcpy(last, line); 904 while ((i = getline(cfp)) != 0) 905 if (strcmp(last, line)) 906 break; 907 switch (sendfile(pp, '\3', last+1, *last)) { 908 case OK: 909 if (i) 910 goto again; 911 break; 912 case REPRINT: 913 (void) fclose(cfp); 914 return(REPRINT); 915 case ACCESS: 916 sendmail(pp, logname, ACCESS); 917 case ERROR: 918 err = ERROR; 919 } 920 break; 921 } 922 } 923 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 924 (void) fclose(cfp); 925 return(REPRINT); 926 } 927 /* 928 * pass 2 929 */ 930 fseek(cfp, 0L, 0); 931 while (getline(cfp)) 932 if (line[0] == 'U' && !strchr(line+1, '/')) 933 (void) unlink(line+1); 934 /* 935 * clean-up in case another control file exists 936 */ 937 (void) fclose(cfp); 938 (void) unlink(file); 939 return(err); 940} 941 942/* 943 * Send a data file to the remote machine and spool it. 944 * Return positive if we should try resending. 945 */ 946static int 947sendfile(pp, type, file, format) 948 struct printer *pp; 949 int type; 950 char *file; 951 char format; 952{ 953 register int f, i, amt; 954 struct stat stb; 955 FILE *fp; 956 char buf[BUFSIZ]; 957 int sizerr, resp, closedpr; 958 959 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 960 return(ERROR); 961 /* 962 * Check to see if data file is a symbolic link. If so, it should 963 * still point to the same file or someone is trying to print something 964 * he shouldn't. 965 */ 966 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 967 (stb.st_dev != fdev || stb.st_ino != fino)) 968 return(ACCESS); 969 970 job_dfcnt++; /* increment datafile counter for this job */ 971 972 /* everything seems OK, start it up */ 973 sizerr = 0; 974 closedpr = 0; 975 if (type == '\3') { 976 if (pp->filters[LPF_INPUT]) { 977 /* 978 * We're sending something with an ifilter, we have to 979 * run the ifilter and store the output as a 980 * temporary file (tfile)... the protocol requires us 981 * to send the file size 982 */ 983 char *av[15]; 984 int n; 985 int ifilter; 986 union wait status; /* XXX */ 987 988 strcpy(tfile,TFILENAME); 989 if ((tfd = mkstemp(tfile)) == -1) { 990 syslog(LOG_ERR, "mkstemp: %m"); 991 return(ERROR); 992 } 993 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 994 av[0] = pp->filters[LPF_INPUT]; 995 else 996 av[0]++; 997 if (format == 'l') 998 av[n=1] = "-c"; 999 else 1000 n = 0; 1001 av[++n] = width; 1002 av[++n] = length; 1003 av[++n] = indent; 1004 av[++n] = "-n"; 1005 av[++n] = logname; 1006 av[++n] = "-h"; 1007 av[++n] = fromhost; 1008 av[++n] = pp->acct_file; 1009 av[++n] = 0; 1010 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 1011 dup2(f, 0); 1012 dup2(tfd, 1); 1013 /* setup stderr for the filter (child process) 1014 * so it goes to our temporary errors file */ 1015 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1016 if (n >= 0) 1017 dup2(n, 2); 1018 closelog(); 1019 closeallfds(3); 1020 execv(pp->filters[LPF_INPUT], av); 1021 syslog(LOG_ERR, "cannot execv %s", 1022 pp->filters[LPF_INPUT]); 1023 exit(2); 1024 } 1025 (void) close(f); 1026 if (ifilter < 0) 1027 status.w_retcode = 100; 1028 else 1029 while ((pid = wait((int *)&status)) > 0 && 1030 pid != ifilter) 1031 ; 1032 /* Copy the filter's output to "lf" logfile */ 1033 if ((fp = fopen(tempstderr, "r"))) { 1034 while (fgets(buf, sizeof(buf), fp)) 1035 fputs(buf, stderr); 1036 fclose(fp); 1037 } 1038 /* process the return-code from the filter */ 1039 switch (status.w_retcode) { 1040 case 0: 1041 break; 1042 case 1: 1043 unlink(tfile); 1044 return(REPRINT); 1045 case 2: 1046 unlink(tfile); 1047 return(ERROR); 1048 default: 1049 syslog(LOG_WARNING, "%s: filter '%c' exited" 1050 " (retcode=%d)", 1051 pp->printer, format, status.w_retcode); 1052 unlink(tfile); 1053 return(FILTERERR); 1054 } 1055 if (fstat(tfd, &stb) < 0) /* the size of tfile */ 1056 return(ERROR); 1057 f = tfd; 1058 lseek(f,0,SEEK_SET); 1059 } else if (ofilter) { 1060 /* 1061 * We're sending something with an ofilter, we have to 1062 * store the output as a temporary file (tfile)... the 1063 * protocol requires us to send the file size 1064 */ 1065 int i; 1066 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1067 amt = BUFSIZ; 1068 if (i + amt > stb.st_size) 1069 amt = stb.st_size - i; 1070 if (sizerr == 0 && read(f, buf, amt) != amt) { 1071 sizerr = 1; 1072 break; 1073 } 1074 if (write(ofd, buf, amt) != amt) { 1075 (void) close(f); 1076 return(REPRINT); 1077 } 1078 } 1079 close(ofd); 1080 close(f); 1081 while ((i = wait(NULL)) > 0 && i != ofilter) 1082 ; 1083 ofilter = 0; 1084 if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 1085 openpr(pp); 1086 return(ERROR); 1087 } 1088 f = tfd; 1089 lseek(f,0,SEEK_SET); 1090 closedpr = 1; 1091 } 1092 } 1093 1094 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1095 amt = strlen(buf); 1096 for (i = 0; ; i++) { 1097 if (write(pfd, buf, amt) != amt || 1098 (resp = response(pp)) < 0 || resp == '\1') { 1099 (void) close(f); 1100 if (tfd != -1 && type == '\3') { 1101 tfd = -1; 1102 unlink(tfile); 1103 if (closedpr) 1104 openpr(pp); 1105 } 1106 return(REPRINT); 1107 } else if (resp == '\0') 1108 break; 1109 if (i == 0) 1110 pstatus(pp, 1111 "no space on remote; waiting for queue to drain"); 1112 if (i == 10) 1113 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1114 pp->printer, pp->remote_host); 1115 sleep(5 * 60); 1116 } 1117 if (i) 1118 pstatus(pp, "sending to %s", pp->remote_host); 1119 if (type == '\3') 1120 trstat_init(pp, file, job_dfcnt); 1121 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1122 amt = BUFSIZ; 1123 if (i + amt > stb.st_size) 1124 amt = stb.st_size - i; 1125 if (sizerr == 0 && read(f, buf, amt) != amt) 1126 sizerr = 1; 1127 if (write(pfd, buf, amt) != amt) { 1128 (void) close(f); 1129 if (tfd != -1 && type == '\3') { 1130 tfd = -1; 1131 unlink(tfile); 1132 if (closedpr) 1133 openpr(pp); 1134 } 1135 return(REPRINT); 1136 } 1137 } 1138 1139 (void) close(f); 1140 if (tfd != -1 && type == '\3') { 1141 tfd = -1; 1142 unlink(tfile); 1143 } 1144 if (sizerr) { 1145 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1146 /* tell recvjob to ignore this file */ 1147 (void) write(pfd, "\1", 1); 1148 if (closedpr) 1149 openpr(pp); 1150 return(ERROR); 1151 } 1152 if (write(pfd, "", 1) != 1 || response(pp)) { 1153 if (closedpr) 1154 openpr(pp); 1155 return(REPRINT); 1156 } 1157 if (closedpr) 1158 openpr(pp); 1159 if (type == '\3') 1160 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1161 pp->remote_host, fromhost); 1162 return(OK); 1163} 1164 1165/* 1166 * Check to make sure there have been no errors and that both programs 1167 * are in sync with eachother. 1168 * Return non-zero if the connection was lost. 1169 */ 1170static char 1171response(pp) 1172 const struct printer *pp; 1173{ 1174 char resp; 1175 1176 if (read(pfd, &resp, 1) != 1) { 1177 syslog(LOG_INFO, "%s: lost connection", pp->printer); 1178 return(-1); 1179 } 1180 return(resp); 1181} 1182 1183/* 1184 * Banner printing stuff 1185 */ 1186static void 1187banner(pp, name1, name2) 1188 struct printer *pp; 1189 char *name1, *name2; 1190{ 1191 time_t tvec; 1192 1193 time(&tvec); 1194 if (!pp->no_formfeed && !pp->tof) 1195 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1196 if (pp->short_banner) { /* short banner only */ 1197 if (class[0]) { 1198 (void) write(ofd, class, strlen(class)); 1199 (void) write(ofd, ":", 1); 1200 } 1201 (void) write(ofd, name1, strlen(name1)); 1202 (void) write(ofd, " Job: ", 7); 1203 (void) write(ofd, name2, strlen(name2)); 1204 (void) write(ofd, " Date: ", 8); 1205 (void) write(ofd, ctime(&tvec), 24); 1206 (void) write(ofd, "\n", 1); 1207 } else { /* normal banner */ 1208 (void) write(ofd, "\n\n\n", 3); 1209 scan_out(pp, ofd, name1, '\0'); 1210 (void) write(ofd, "\n\n", 2); 1211 scan_out(pp, ofd, name2, '\0'); 1212 if (class[0]) { 1213 (void) write(ofd,"\n\n\n",3); 1214 scan_out(pp, ofd, class, '\0'); 1215 } 1216 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1217 (void) write(ofd, name2, strlen(name2)); 1218 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1219 (void) write(ofd, ctime(&tvec), 24); 1220 (void) write(ofd, "\n", 1); 1221 } 1222 if (!pp->no_formfeed) 1223 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1224 pp->tof = 1; 1225} 1226 1227static char * 1228scnline(key, p, c) 1229 register int key; 1230 register char *p; 1231 int c; 1232{ 1233 register int scnwidth; 1234 1235 for (scnwidth = WIDTH; --scnwidth;) { 1236 key <<= 1; 1237 *p++ = key & 0200 ? c : BACKGND; 1238 } 1239 return (p); 1240} 1241 1242#define TRC(q) (((q)-' ')&0177) 1243 1244static void 1245scan_out(pp, scfd, scsp, dlm) 1246 struct printer *pp; 1247 int scfd, dlm; 1248 char *scsp; 1249{ 1250 register char *strp; 1251 register int nchrs, j; 1252 char outbuf[LINELEN+1], *sp, c, cc; 1253 int d, scnhgt; 1254 1255 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1256 strp = &outbuf[0]; 1257 sp = scsp; 1258 for (nchrs = 0; ; ) { 1259 d = dropit(c = TRC(cc = *sp++)); 1260 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1261 for (j = WIDTH; --j;) 1262 *strp++ = BACKGND; 1263 else 1264 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1265 if (*sp == dlm || *sp == '\0' || 1266 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1267 break; 1268 *strp++ = BACKGND; 1269 *strp++ = BACKGND; 1270 } 1271 while (*--strp == BACKGND && strp >= outbuf) 1272 ; 1273 strp++; 1274 *strp++ = '\n'; 1275 (void) write(scfd, outbuf, strp-outbuf); 1276 } 1277} 1278 1279static int 1280dropit(c) 1281 int c; 1282{ 1283 switch(c) { 1284 1285 case TRC('_'): 1286 case TRC(';'): 1287 case TRC(','): 1288 case TRC('g'): 1289 case TRC('j'): 1290 case TRC('p'): 1291 case TRC('q'): 1292 case TRC('y'): 1293 return (DROP); 1294 1295 default: 1296 return (0); 1297 } 1298} 1299 1300/* 1301 * sendmail --- 1302 * tell people about job completion 1303 */ 1304static void 1305sendmail(pp, user, bombed) 1306 struct printer *pp; 1307 char *user; 1308 int bombed; 1309{ 1310 register int i; 1311 int p[2], s; 1312 register char *cp; 1313 struct stat stb; 1314 FILE *fp; 1315 1316 pipe(p); 1317 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1318 dup2(p[0], 0); 1319 closelog(); 1320 closeallfds(3); 1321 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1322 cp++; 1323 else 1324 cp = _PATH_SENDMAIL; 1325 execl(_PATH_SENDMAIL, cp, "-t", 0); 1326 _exit(0); 1327 } else if (s > 0) { /* parent */ 1328 dup2(p[1], 1); 1329 printf("To: %s@%s\n", user, fromhost); 1330 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1331 *jobname ? jobname : "<unknown>"); 1332 printf("Reply-To: root@%s\n\n", host); 1333 printf("Your printer job "); 1334 if (*jobname) 1335 printf("(%s) ", jobname); 1336 1337 cp = "XXX compiler confusion"; /* XXX shut GCC up */ 1338 switch (bombed) { 1339 case OK: 1340 printf("\ncompleted successfully\n"); 1341 cp = "OK"; 1342 break; 1343 default: 1344 case FATALERR: 1345 printf("\ncould not be printed\n"); 1346 cp = "FATALERR"; 1347 break; 1348 case NOACCT: 1349 printf("\ncould not be printed without an account on %s\n", host); 1350 cp = "NOACCT"; 1351 break; 1352 case FILTERERR: 1353 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1354 || (fp = fopen(tempstderr, "r")) == NULL) { 1355 printf("\nhad some errors and may not have printed\n"); 1356 break; 1357 } 1358 printf("\nhad the following errors and may not have printed:\n"); 1359 while ((i = getc(fp)) != EOF) 1360 putchar(i); 1361 (void) fclose(fp); 1362 cp = "FILTERERR"; 1363 break; 1364 case ACCESS: 1365 printf("\nwas not printed because it was not linked to the original file\n"); 1366 cp = "ACCESS"; 1367 } 1368 fflush(stdout); 1369 (void) close(1); 1370 } else { 1371 syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 1372 return; 1373 } 1374 (void) close(p[0]); 1375 (void) close(p[1]); 1376 wait(NULL); 1377 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1378 user, *jobname ? jobname : "<unknown>", pp->printer, cp); 1379} 1380 1381/* 1382 * dofork - fork with retries on failure 1383 */ 1384static int 1385dofork(pp, action) 1386 const struct printer *pp; 1387 int action; 1388{ 1389 register int i, pid; 1390 struct passwd *pwd; 1391 1392 for (i = 0; i < 20; i++) { 1393 if ((pid = fork()) < 0) { 1394 sleep((unsigned)(i*i)); 1395 continue; 1396 } 1397 /* 1398 * Child should run as daemon instead of root 1399 */ 1400 if (pid == 0) { 1401 if ((pwd = getpwuid(pp->daemon_user)) == NULL) { 1402 syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", 1403 pp->daemon_user); 1404 break; 1405 } 1406 initgroups(pwd->pw_name, pwd->pw_gid); 1407 setgid(pwd->pw_gid); 1408 setuid(pp->daemon_user); 1409 } 1410 return(pid); 1411 } 1412 syslog(LOG_ERR, "can't fork"); 1413 1414 switch (action) { 1415 case DORETURN: 1416 return (-1); 1417 default: 1418 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1419 /*FALL THRU*/ 1420 case DOABORT: 1421 exit(1); 1422 } 1423 /*NOTREACHED*/ 1424} 1425 1426/* 1427 * Kill child processes to abort current job. 1428 */ 1429static void 1430abortpr(signo) 1431 int signo; 1432{ 1433 1434 (void) unlink(tempstderr); 1435 kill(0, SIGINT); 1436 if (ofilter > 0) 1437 kill(ofilter, SIGCONT); 1438 while (wait(NULL) > 0) 1439 ; 1440 if (ofilter > 0 && tfd != -1) 1441 unlink(tfile); 1442 exit(0); 1443} 1444 1445static void 1446init(pp) 1447 struct printer *pp; 1448{ 1449 char *s; 1450 1451 sprintf(&width[2], "%ld", pp->page_width); 1452 sprintf(&length[2], "%ld", pp->page_length); 1453 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1454 sprintf(&pxlength[2], "%ld", pp->page_plength); 1455 if ((s = checkremote(pp)) != 0) { 1456 syslog(LOG_WARNING, "%s", s); 1457 free(s); 1458 } 1459} 1460 1461void 1462startprinting(printer) 1463 const char *printer; 1464{ 1465 struct printer myprinter, *pp = &myprinter; 1466 int status; 1467 1468 init_printer(pp); 1469 status = getprintcap(printer, pp); 1470 switch(status) { 1471 case PCAPERR_OSERR: 1472 syslog(LOG_ERR, "can't open printer description file: %m"); 1473 exit(1); 1474 case PCAPERR_NOTFOUND: 1475 syslog(LOG_ERR, "unknown printer: %s", printer); 1476 exit(1); 1477 case PCAPERR_TCLOOP: 1478 fatal(pp, "potential reference loop detected in printcap file"); 1479 default: 1480 break; 1481 } 1482 printjob(pp); 1483} 1484 1485/* 1486 * Acquire line printer or remote connection. 1487 */ 1488static void 1489openpr(pp) 1490 const struct printer *pp; 1491{ 1492 int p[2]; 1493 char *cp; 1494 1495 if (pp->remote) { 1496 openrem(pp); 1497 } else if (*pp->lp) { 1498 if ((cp = strchr(pp->lp, '@')) != NULL) 1499 opennet(pp); 1500 else 1501 opentty(pp); 1502 } else { 1503 syslog(LOG_ERR, "%s: no line printer device or host name", 1504 pp->printer); 1505 exit(1); 1506 } 1507 1508 /* 1509 * Start up an output filter, if needed. 1510 */ 1511 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1512 pipe(p); 1513 if (pp->remote) { 1514 strcpy(tfile, TFILENAME); 1515 tfd = mkstemp(tfile); 1516 } 1517 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1518 dup2(p[0], 0); /* pipe is std in */ 1519 /* tfile/printer is stdout */ 1520 dup2(pp->remote ? tfd : pfd, 1); 1521 closelog(); 1522 closeallfds(3); 1523 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1524 cp = pp->filters[LPF_OUTPUT]; 1525 else 1526 cp++; 1527 execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); 1528 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1529 pp->filters[LPF_OUTPUT]); 1530 exit(1); 1531 } 1532 (void) close(p[0]); /* close input side */ 1533 ofd = p[1]; /* use pipe for output */ 1534 } else { 1535 ofd = pfd; 1536 ofilter = 0; 1537 } 1538} 1539 1540/* 1541 * Printer connected directly to the network 1542 * or to a terminal server on the net 1543 */ 1544static void 1545opennet(pp) 1546 const struct printer *pp; 1547{ 1548 register int i; 1549 int resp; 1550 u_long port; 1551 char *ep; 1552 void (*savealrm)(int); 1553 1554 port = strtoul(pp->lp, &ep, 0); 1555 if (*ep != '@' || port > 65535) { 1556 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1557 pp->lp); 1558 exit(1); 1559 } 1560 ep++; 1561 1562 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1563 resp = -1; 1564 savealrm = signal(SIGALRM, alarmhandler); 1565 alarm(pp->conn_timeout); 1566 pfd = getport(pp, ep, port); 1567 alarm(0); 1568 (void)signal(SIGALRM, savealrm); 1569 if (pfd < 0 && errno == ECONNREFUSED) 1570 resp = 1; 1571 else if (pfd >= 0) { 1572 /* 1573 * need to delay a bit for rs232 lines 1574 * to stabilize in case printer is 1575 * connected via a terminal server 1576 */ 1577 delay(500); 1578 break; 1579 } 1580 if (i == 1) { 1581 if (resp < 0) 1582 pstatus(pp, "waiting for %s to come up", 1583 pp->lp); 1584 else 1585 pstatus(pp, 1586 "waiting for access to printer on %s", 1587 pp->lp); 1588 } 1589 sleep(i); 1590 } 1591 pstatus(pp, "sending to %s port %d", ep, port); 1592} 1593 1594/* 1595 * Printer is connected to an RS232 port on this host 1596 */ 1597static void 1598opentty(pp) 1599 const struct printer *pp; 1600{ 1601 register int i; 1602 1603 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1604 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1605 if (pfd >= 0) { 1606 delay(500); 1607 break; 1608 } 1609 if (errno == ENOENT) { 1610 syslog(LOG_ERR, "%s: %m", pp->lp); 1611 exit(1); 1612 } 1613 if (i == 1) 1614 pstatus(pp, 1615 "waiting for %s to become ready (offline?)", 1616 pp->printer); 1617 sleep(i); 1618 } 1619 if (isatty(pfd)) 1620 setty(pp); 1621 pstatus(pp, "%s is ready and printing", pp->printer); 1622} 1623 1624/* 1625 * Printer is on a remote host 1626 */ 1627static void 1628openrem(pp) 1629 const struct printer *pp; 1630{ 1631 register int i; 1632 int resp; 1633 void (*savealrm)(int); 1634 1635 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1636 resp = -1; 1637 savealrm = signal(SIGALRM, alarmhandler); 1638 alarm(pp->conn_timeout); 1639 pfd = getport(pp, pp->remote_host, 0); 1640 alarm(0); 1641 (void)signal(SIGALRM, savealrm); 1642 if (pfd >= 0) { 1643 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1644 (char *)0) 1645 == 2 + strlen(pp->remote_queue)) 1646 && (resp = response(pp)) == 0) 1647 break; 1648 (void) close(pfd); 1649 } 1650 if (i == 1) { 1651 if (resp < 0) 1652 pstatus(pp, "waiting for %s to come up", 1653 pp->remote_host); 1654 else { 1655 pstatus(pp, 1656 "waiting for queue to be enabled on %s", 1657 pp->remote_host); 1658 i = 256; 1659 } 1660 } 1661 sleep(i); 1662 } 1663 pstatus(pp, "sending to %s", pp->remote_host); 1664} 1665 1666/* 1667 * setup tty lines. 1668 */ 1669static void 1670setty(pp) 1671 const struct printer *pp; 1672{ 1673 struct termios ttybuf; 1674 1675 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1676 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1677 exit(1); 1678 } 1679 if (tcgetattr(pfd, &ttybuf) < 0) { 1680 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1681 exit(1); 1682 } 1683 if (pp->baud_rate > 0) 1684 cfsetspeed(&ttybuf, pp->baud_rate); 1685 if (pp->mode_set) { 1686 char *s = strdup(pp->mode_set), *tmp; 1687 1688 while ((tmp = strsep(&s, ",")) != NULL) { 1689 (void) msearch(tmp, &ttybuf); 1690 } 1691 } 1692 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1693 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1694 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1695 } 1696 } 1697} 1698 1699#ifdef __STDC__ 1700#include <stdarg.h> 1701#else 1702#include <varargs.h> 1703#endif 1704 1705static void 1706#ifdef __STDC__ 1707pstatus(const struct printer *pp, const char *msg, ...) 1708#else 1709pstatus(pp, msg, va_alist) 1710 const struct printer *pp; 1711 char *msg; 1712 va_dcl 1713#endif 1714{ 1715 int fd; 1716 char *buf; 1717 va_list ap; 1718#ifdef __STDC__ 1719 va_start(ap, msg); 1720#else 1721 va_start(ap); 1722#endif 1723 1724 umask(0); 1725 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1726 if (fd < 0) { 1727 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1728 exit(1); 1729 } 1730 ftruncate(fd, 0); 1731 vasprintf(&buf, msg, ap); 1732 va_end(ap); 1733 writel(fd, buf, "\n", (char *)0); 1734 close(fd); 1735 free(buf); 1736} 1737 1738void 1739alarmhandler(signo) 1740{ 1741 /* ignored */ 1742} 1743