printjob.c revision 74124
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * 61553Srgrimes * Redistribution and use in source and binary forms, with or without 71553Srgrimes * modification, are permitted provided that the following conditions 81553Srgrimes * are met: 91553Srgrimes * 1. Redistributions of source code must retain the above copyright 101553Srgrimes * notice, this list of conditions and the following disclaimer. 111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121553Srgrimes * notice, this list of conditions and the following disclaimer in the 131553Srgrimes * documentation and/or other materials provided with the distribution. 141553Srgrimes * 3. All advertising materials mentioning features or use of this software 151553Srgrimes * must display the following acknowledgement: 161553Srgrimes * This product includes software developed by the University of 171553Srgrimes * California, Berkeley and its contributors. 181553Srgrimes * 4. Neither the name of the University nor the names of its contributors 191553Srgrimes * may be used to endorse or promote products derived from this software 201553Srgrimes * without specific prior written permission. 211553Srgrimes * 221553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321553Srgrimes * SUCH DAMAGE. 331553Srgrimes */ 341553Srgrimes 351553Srgrimes#ifndef lint 3631492Swollmanstatic const char copyright[] = 371553Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 381553Srgrimes The Regents of the University of California. All rights reserved.\n"; 391553Srgrimes#endif /* not lint */ 401553Srgrimes 411553Srgrimes#ifndef lint 4231492Swollman/* 4315648Sjoergstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 4431492Swollman*/ 4531492Swollmanstatic const char rcsid[] = 4650479Speter "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 74124 2001-03-12 00:22:03Z gad $"; 471553Srgrimes#endif /* not lint */ 481553Srgrimes 491553Srgrimes 501553Srgrimes/* 511553Srgrimes * printjob -- print jobs in the queue. 521553Srgrimes * 531553Srgrimes * NOTE: the lock file is used to pass information to lpq and lprm. 541553Srgrimes * it does not need to be removed because file locks are dynamic. 551553Srgrimes */ 561553Srgrimes 571553Srgrimes#include <sys/param.h> 581553Srgrimes#include <sys/wait.h> 591553Srgrimes#include <sys/stat.h> 601553Srgrimes#include <sys/types.h> 611553Srgrimes 621553Srgrimes#include <pwd.h> 631553Srgrimes#include <unistd.h> 641553Srgrimes#include <signal.h> 651553Srgrimes#include <syslog.h> 661553Srgrimes#include <fcntl.h> 671553Srgrimes#include <dirent.h> 681553Srgrimes#include <errno.h> 691553Srgrimes#include <stdio.h> 701553Srgrimes#include <string.h> 711553Srgrimes#include <stdlib.h> 7215032Ssef#include <sys/ioctl.h> 7315032Ssef#include <termios.h> 7415703Sjoerg#include <time.h> 751553Srgrimes#include "lp.h" 761553Srgrimes#include "lp.local.h" 771553Srgrimes#include "pathnames.h" 781553Srgrimes#include "extern.h" 791553Srgrimes 801553Srgrimes#define DORETURN 0 /* absorb fork error */ 811553Srgrimes#define DOABORT 1 /* abort if dofork fails */ 821553Srgrimes 831553Srgrimes/* 841553Srgrimes * Error tokens 851553Srgrimes */ 861553Srgrimes#define REPRINT -2 871553Srgrimes#define ERROR -1 881553Srgrimes#define OK 0 891553Srgrimes#define FATALERR 1 901553Srgrimes#define NOACCT 2 911553Srgrimes#define FILTERERR 3 921553Srgrimes#define ACCESS 4 931553Srgrimes 941553Srgrimesstatic dev_t fdev; /* device of file pointed to by symlink */ 951553Srgrimesstatic ino_t fino; /* inode of file pointed to by symlink */ 961553Srgrimesstatic FILE *cfp; /* control file */ 971553Srgrimesstatic int child; /* id of any filters */ 9868253Sgadstatic int job_dfcnt; /* count of datafiles in current user job */ 991553Srgrimesstatic int lfd; /* lock file descriptor */ 1001553Srgrimesstatic int ofd; /* output filter file descriptor */ 1011553Srgrimesstatic int ofilter; /* id of output filter, if any */ 10224831Sbrianstatic int tfd = -1; /* output filter temp file output */ 1031553Srgrimesstatic int pfd; /* prstatic inter file descriptor */ 1041553Srgrimesstatic int pid; /* pid of lpd process */ 1051553Srgrimesstatic int prchild; /* id of pr process */ 1061553Srgrimesstatic char title[80]; /* ``pr'' title */ 10753956Sachestatic char locale[80]; /* ``pr'' locale */ 1081553Srgrimes 1091553Srgrimesstatic char class[32]; /* classification field */ 11068343Sgadstatic char fromhost[MAXHOSTNAMELEN]; /* user's host machine */ 1111553Srgrimes /* indentation size in static characters */ 1128857Srgrimesstatic char indent[10] = "-i0"; 1131553Srgrimesstatic char jobname[100]; /* job or file name */ 1141553Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1151553Srgrimesstatic char logname[32]; /* user's login name */ 1161553Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1171553Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 11868664Sgad/* tempstderr is the filename used to catch stderr from exec-ing filters */ 11968664Sgadstatic char tempstderr[] = "errs.XXXXXXX"; 1201553Srgrimesstatic char width[10] = "-w"; /* page width in static characters */ 12124831Sbrian#define TFILENAME "fltXXXXXX" 12224831Sbrianstatic char tfile[] = TFILENAME; /* file name for filter output */ 1231553Srgrimes 1241553Srgrimesstatic void abortpr __P((int)); 12530407Sjoergstatic void alarmhandler __P((int)); 12631492Swollmanstatic void banner __P((struct printer *pp, char *name1, char *name2)); 12731492Swollmanstatic int dofork __P((const struct printer *pp, int action)); 1281553Srgrimesstatic int dropit __P((int)); 12931492Swollmanstatic void init __P((struct printer *pp)); 13031492Swollmanstatic void openpr __P((const struct printer *pp)); 13131492Swollmanstatic void opennet __P((const struct printer *pp)); 13231492Swollmanstatic void opentty __P((const struct printer *pp)); 13331492Swollmanstatic void openrem __P((const struct printer *pp)); 13431492Swollmanstatic int print __P((struct printer *pp, int format, char *file)); 13531492Swollmanstatic int printit __P((struct printer *pp, char *file)); 13631492Swollmanstatic void pstatus __P((const struct printer *, const char *, ...)); 13731492Swollmanstatic char response __P((const struct printer *pp)); 13831492Swollmanstatic void scan_out __P((struct printer *pp, int scfd, char *scsp, 13931492Swollman int dlm)); 1401553Srgrimesstatic char *scnline __P((int, char *, int)); 14131492Swollmanstatic int sendfile __P((struct printer *pp, int type, char *file, 14231492Swollman int format)); 14331492Swollmanstatic int sendit __P((struct printer *pp, char *file)); 14431492Swollmanstatic void sendmail __P((struct printer *pp, char *user, int bombed)); 14531492Swollmanstatic void setty __P((const struct printer *pp)); 1461553Srgrimes 1471553Srgrimesvoid 14831492Swollmanprintjob(pp) 14931492Swollman struct printer *pp; 1501553Srgrimes{ 1511553Srgrimes struct stat stb; 15268401Sgad register struct jobqueue *q, **qp; 15368401Sgad struct jobqueue **queue; 1541553Srgrimes register int i, nitems; 15568733Sgad off_t pidoff; 15668733Sgad int errcnt, jobcount, tempfd; 1571553Srgrimes 15868733Sgad jobcount = 0; 15931492Swollman init(pp); /* set up capabilities */ 16031492Swollman (void) write(1, "", 1); /* ack that daemon is started */ 1611553Srgrimes (void) close(2); /* set up log file */ 16231492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 16331492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1641553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1651553Srgrimes } 1661553Srgrimes setgid(getegid()); 1671553Srgrimes pid = getpid(); /* for use with lprm */ 1681553Srgrimes setpgrp(0, pid); 1691553Srgrimes signal(SIGHUP, abortpr); 1701553Srgrimes signal(SIGINT, abortpr); 1711553Srgrimes signal(SIGQUIT, abortpr); 1721553Srgrimes signal(SIGTERM, abortpr); 1731553Srgrimes 1741553Srgrimes /* 1751553Srgrimes * uses short form file names 1761553Srgrimes */ 17731492Swollman if (chdir(pp->spool_dir) < 0) { 17831492Swollman syslog(LOG_ERR, "%s: %m", pp->spool_dir); 1791553Srgrimes exit(1); 1801553Srgrimes } 18131492Swollman if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 1821553Srgrimes exit(0); /* printing disabled */ 18331492Swollman lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 18431492Swollman LOCK_FILE_MODE); 1851553Srgrimes if (lfd < 0) { 18631492Swollman if (errno == EWOULDBLOCK) /* active daemon present */ 18731492Swollman exit(0); 18831492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 1891553Srgrimes exit(1); 1901553Srgrimes } 19131492Swollman /* turn off non-blocking mode (was turned on for lock effects only) */ 19231492Swollman if (fcntl(lfd, F_SETFL, 0) < 0) { 19331492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 1941553Srgrimes exit(1); 1951553Srgrimes } 1961553Srgrimes ftruncate(lfd, 0); 1971553Srgrimes /* 1981553Srgrimes * write process id for others to know 1991553Srgrimes */ 2001553Srgrimes sprintf(line, "%u\n", pid); 2011553Srgrimes pidoff = i = strlen(line); 2021553Srgrimes if (write(lfd, line, i) != i) { 20331492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 2041553Srgrimes exit(1); 2051553Srgrimes } 2061553Srgrimes /* 2071553Srgrimes * search the spool directory for work and sort by queue order. 2081553Srgrimes */ 20931492Swollman if ((nitems = getq(pp, &queue)) < 0) { 21031492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 21131492Swollman pp->spool_dir); 2121553Srgrimes exit(1); 2131553Srgrimes } 2141553Srgrimes if (nitems == 0) /* no work to do */ 2151553Srgrimes exit(0); 21631492Swollman if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 21731492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 21831492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 21931492Swollman pp->lock_file); 2201553Srgrimes } 22168664Sgad 22268664Sgad /* create a file which will be used to hold stderr from filters */ 22368664Sgad if ((tempfd = mkstemp(tempstderr)) == -1) { 22468664Sgad syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 22568664Sgad tempstderr); 22668732Sgad exit(1); 22768664Sgad } 22868664Sgad if ((i = fchmod(tempfd, 0664)) == -1) { 22968664Sgad syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 23068664Sgad tempstderr); 23168732Sgad exit(1); 23268664Sgad } 23368664Sgad /* lpd doesn't need it to be open, it just needs it to exist */ 23468664Sgad close(tempfd); 23568664Sgad 23631492Swollman openpr(pp); /* open printer or remote */ 2371553Srgrimesagain: 2381553Srgrimes /* 2391553Srgrimes * we found something to do now do it -- 2401553Srgrimes * write the name of the current control file into the lock file 2411553Srgrimes * so the spool queue program can tell what we're working on 2421553Srgrimes */ 2431553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2441553Srgrimes q = *qp++; 24568401Sgad if (stat(q->job_cfname, &stb) < 0) 2461553Srgrimes continue; 24715648Sjoerg errcnt = 0; 2481553Srgrimes restart: 24915648Sjoerg (void) lseek(lfd, pidoff, 0); 25068401Sgad (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 2511553Srgrimes i = strlen(line); 2521553Srgrimes if (write(lfd, line, i) != i) 25331492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 25431492Swollman pp->lock_file); 25531492Swollman if (!pp->remote) 25668401Sgad i = printit(pp, q->job_cfname); 2571553Srgrimes else 25868401Sgad i = sendit(pp, q->job_cfname); 2591553Srgrimes /* 2601553Srgrimes * Check to see if we are supposed to stop printing or 2611553Srgrimes * if we are to rebuild the queue. 2621553Srgrimes */ 2631553Srgrimes if (fstat(lfd, &stb) == 0) { 2641553Srgrimes /* stop printing before starting next job? */ 26531492Swollman if (stb.st_mode & LFM_PRINT_DIS) 2661553Srgrimes goto done; 2671553Srgrimes /* rebuild queue (after lpc topq) */ 26831492Swollman if (stb.st_mode & LFM_RESET_QUE) { 26931492Swollman for (free(q); nitems--; free(q)) 2701553Srgrimes q = *qp++; 27131492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 27231492Swollman < 0) 2731553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 27431492Swollman pp->printer, pp->lock_file); 2751553Srgrimes break; 2761553Srgrimes } 2771553Srgrimes } 27868733Sgad if (i == OK) /* all files of this job printed */ 27968733Sgad jobcount++; 28015648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 28115648Sjoerg /* try reprinting the job */ 28231492Swollman syslog(LOG_INFO, "restarting %s", pp->printer); 2831553Srgrimes if (ofilter > 0) { 2841553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2851553Srgrimes (void) close(ofd); 28615648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2871553Srgrimes ; 2881553Srgrimes ofilter = 0; 2891553Srgrimes } 2901553Srgrimes (void) close(pfd); /* close printer */ 2911553Srgrimes if (ftruncate(lfd, pidoff) < 0) 29231492Swollman syslog(LOG_WARNING, "%s: %s: %m", 29331492Swollman pp->printer, pp->lock_file); 29431492Swollman openpr(pp); /* try to reopen printer */ 2951553Srgrimes goto restart; 29615648Sjoerg } else { 29731492Swollman syslog(LOG_WARNING, "%s: job could not be %s (%s)", 29831492Swollman pp->printer, 29931492Swollman pp->remote ? "sent to remote host" : "printed", 30068401Sgad q->job_cfname); 30115648Sjoerg if (i == REPRINT) { 30227748Simp /* ensure we don't attempt this job again */ 30368401Sgad (void) unlink(q->job_cfname); 30468401Sgad q->job_cfname[0] = 'd'; 30568401Sgad (void) unlink(q->job_cfname); 30615648Sjoerg if (logname[0]) 30731492Swollman sendmail(pp, logname, FATALERR); 30815648Sjoerg } 3091553Srgrimes } 3101553Srgrimes } 31131492Swollman free(queue); 3121553Srgrimes /* 3131553Srgrimes * search the spool directory for more work. 3141553Srgrimes */ 31531492Swollman if ((nitems = getq(pp, &queue)) < 0) { 31631492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 31731492Swollman pp->spool_dir); 3181553Srgrimes exit(1); 3191553Srgrimes } 3201553Srgrimes if (nitems == 0) { /* no more work to do */ 3211553Srgrimes done: 32268733Sgad if (jobcount > 0) { /* jobs actually printed */ 32331492Swollman if (!pp->no_formfeed && !pp->tof) 32431492Swollman (void) write(ofd, pp->form_feed, 32531492Swollman strlen(pp->form_feed)); 32631492Swollman if (pp->trailer != NULL) /* output trailer */ 32731492Swollman (void) write(ofd, pp->trailer, 32831492Swollman strlen(pp->trailer)); 3291553Srgrimes } 33019202Simp (void) close(ofd); 33119202Simp (void) wait(NULL); 33268664Sgad (void) unlink(tempstderr); 3331553Srgrimes exit(0); 3341553Srgrimes } 3351553Srgrimes goto again; 3361553Srgrimes} 3371553Srgrimes 3381553Srgrimeschar fonts[4][50]; /* fonts for troff */ 3391553Srgrimes 3401553Srgrimeschar ifonts[4][40] = { 3411553Srgrimes _PATH_VFONTR, 3421553Srgrimes _PATH_VFONTI, 3431553Srgrimes _PATH_VFONTB, 3441553Srgrimes _PATH_VFONTS, 3451553Srgrimes}; 3461553Srgrimes 3471553Srgrimes/* 3481553Srgrimes * The remaining part is the reading of the control file (cf) 3491553Srgrimes * and performing the various actions. 3501553Srgrimes */ 3511553Srgrimesstatic int 35231492Swollmanprintit(pp, file) 35331492Swollman struct printer *pp; 3541553Srgrimes char *file; 3551553Srgrimes{ 3561553Srgrimes register int i; 35768734Sgad char *cp; 35868734Sgad int bombed, didignorehdr; 3591553Srgrimes 36068734Sgad bombed = OK; 36168734Sgad didignorehdr = 0; 3621553Srgrimes /* 3631553Srgrimes * open control file; ignore if no longer there. 3641553Srgrimes */ 3651553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 36631492Swollman syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 3671553Srgrimes return(OK); 3681553Srgrimes } 3691553Srgrimes /* 3701553Srgrimes * Reset troff fonts. 3711553Srgrimes */ 3721553Srgrimes for (i = 0; i < 4; i++) 3731553Srgrimes strcpy(fonts[i], ifonts[i]); 37431492Swollman sprintf(&width[2], "%ld", pp->page_width); 3751553Srgrimes strcpy(indent+2, "0"); 3761553Srgrimes 37768253Sgad /* initialize job-specific count of datafiles processed */ 37868253Sgad job_dfcnt = 0; 37968253Sgad 3801553Srgrimes /* 3811553Srgrimes * read the control file for work to do 3821553Srgrimes * 3831553Srgrimes * file format -- first character in the line is a command 3841553Srgrimes * rest of the line is the argument. 3851553Srgrimes * valid commands are: 3861553Srgrimes * 3871553Srgrimes * S -- "stat info" for symbolic link protection 3881553Srgrimes * J -- "job name" on banner page 3891553Srgrimes * C -- "class name" on banner page 3901553Srgrimes * L -- "literal" user's name to print on banner 3911553Srgrimes * T -- "title" for pr 3921553Srgrimes * H -- "host name" of machine where lpr was done 3931553Srgrimes * P -- "person" user's login name 3941553Srgrimes * I -- "indent" amount to indent output 39515648Sjoerg * R -- laser dpi "resolution" 3961553Srgrimes * f -- "file name" name of text file to print 3971553Srgrimes * l -- "file name" text file with control chars 3981553Srgrimes * p -- "file name" text file to print with pr(1) 3991553Srgrimes * t -- "file name" troff(1) file to print 4001553Srgrimes * n -- "file name" ditroff(1) file to print 4011553Srgrimes * d -- "file name" dvi file to print 4021553Srgrimes * g -- "file name" plot(1G) file to print 4031553Srgrimes * v -- "file name" plain raster file to print 4041553Srgrimes * c -- "file name" cifplot file to print 4051553Srgrimes * 1 -- "R font file" for troff 4061553Srgrimes * 2 -- "I font file" for troff 4071553Srgrimes * 3 -- "B font file" for troff 4081553Srgrimes * 4 -- "S font file" for troff 4091553Srgrimes * N -- "name" of file (used by lpq) 4101553Srgrimes * U -- "unlink" name of file to remove 4111553Srgrimes * (after we print it. (Pass 2 only)). 4121553Srgrimes * M -- "mail" to user when done printing 41353956Sache * Z -- "locale" for pr 4141553Srgrimes * 4151553Srgrimes * getline reads a line and expands tabs to blanks 4161553Srgrimes */ 4171553Srgrimes 4181553Srgrimes /* pass 1 */ 4191553Srgrimes 4201553Srgrimes while (getline(cfp)) 4211553Srgrimes switch (line[0]) { 4221553Srgrimes case 'H': 42327748Simp strncpy(fromhost, line+1, sizeof(fromhost) - 1); 42427748Simp fromhost[sizeof(fromhost) - 1] = '\0'; 42527748Simp if (class[0] == '\0') { 42627748Simp strncpy(class, line+1, sizeof(class) - 1); 42727748Simp class[sizeof(class) - 1] = '\0'; 42827748Simp } 4291553Srgrimes continue; 4301553Srgrimes 4311553Srgrimes case 'P': 43227748Simp strncpy(logname, line+1, sizeof(logname) - 1); 43327748Simp logname[sizeof(logname) - 1] = '\0'; 43431492Swollman if (pp->restricted) { /* restricted */ 4351553Srgrimes if (getpwnam(logname) == NULL) { 4361553Srgrimes bombed = NOACCT; 43731492Swollman sendmail(pp, line+1, bombed); 4381553Srgrimes goto pass2; 4391553Srgrimes } 4401553Srgrimes } 4411553Srgrimes continue; 4421553Srgrimes 4431553Srgrimes case 'S': 4441553Srgrimes cp = line+1; 4451553Srgrimes i = 0; 4461553Srgrimes while (*cp >= '0' && *cp <= '9') 4471553Srgrimes i = i * 10 + (*cp++ - '0'); 4481553Srgrimes fdev = i; 4491553Srgrimes cp++; 4501553Srgrimes i = 0; 4511553Srgrimes while (*cp >= '0' && *cp <= '9') 4521553Srgrimes i = i * 10 + (*cp++ - '0'); 4531553Srgrimes fino = i; 4541553Srgrimes continue; 4551553Srgrimes 4561553Srgrimes case 'J': 45727748Simp if (line[1] != '\0') { 45827748Simp strncpy(jobname, line+1, sizeof(jobname) - 1); 45927748Simp jobname[sizeof(jobname) - 1] = '\0'; 46027748Simp } else 4611553Srgrimes strcpy(jobname, " "); 4621553Srgrimes continue; 4631553Srgrimes 4641553Srgrimes case 'C': 4651553Srgrimes if (line[1] != '\0') 46627748Simp strncpy(class, line+1, sizeof(class) - 1); 4671553Srgrimes else if (class[0] == '\0') 4681553Srgrimes gethostname(class, sizeof(class)); 46927748Simp class[sizeof(class) - 1] = '\0'; 4701553Srgrimes continue; 4711553Srgrimes 4721553Srgrimes case 'T': /* header title for pr */ 47327748Simp strncpy(title, line+1, sizeof(title) - 1); 47427748Simp title[sizeof(title) - 1] = '\0'; 4751553Srgrimes continue; 4761553Srgrimes 4771553Srgrimes case 'L': /* identification line */ 47831492Swollman if (!pp->no_header && !pp->header_last) 47931492Swollman banner(pp, line+1, jobname); 4801553Srgrimes continue; 4811553Srgrimes 4821553Srgrimes case '1': /* troff fonts */ 4831553Srgrimes case '2': 4841553Srgrimes case '3': 4851553Srgrimes case '4': 48627748Simp if (line[1] != '\0') { 48727748Simp strncpy(fonts[line[0]-'1'], line+1, 48827748Simp 50-1); 48927748Simp fonts[line[0]-'1'][50-1] = '\0'; 49027748Simp } 4911553Srgrimes continue; 4921553Srgrimes 4931553Srgrimes case 'W': /* page width */ 49427748Simp strncpy(width+2, line+1, sizeof(width) - 3); 49527748Simp width[2+sizeof(width) - 3] = '\0'; 4961553Srgrimes continue; 4971553Srgrimes 4981553Srgrimes case 'I': /* indent amount */ 49927748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 50027748Simp indent[2+sizeof(indent) - 3] = '\0'; 5011553Srgrimes continue; 5021553Srgrimes 50353956Sache case 'Z': /* locale for pr */ 50453956Sache strncpy(locale, line+1, sizeof(locale) - 1); 50553956Sache locale[sizeof(locale) - 1] = '\0'; 50653956Sache continue; 50753956Sache 5081553Srgrimes default: /* some file to print */ 50968467Sgad /* only lowercase cmd-codes include a file-to-print */ 51068467Sgad if ((line[0] < 'a') || (line[0] > 'z')) { 51168467Sgad /* ignore any other lines */ 51268467Sgad if (lflag <= 1) 51368467Sgad continue; 51468467Sgad if (!didignorehdr) { 51568467Sgad syslog(LOG_INFO, "%s: in %s :", 51668467Sgad pp->printer, file); 51768467Sgad didignorehdr = 1; 51868467Sgad } 51968467Sgad syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 52068467Sgad pp->printer, line[0], &line[1]); 52168467Sgad continue; 52268467Sgad } 52368467Sgad i = print(pp, line[0], line+1); 52468467Sgad switch (i) { 5251553Srgrimes case ERROR: 5261553Srgrimes if (bombed == OK) 5271553Srgrimes bombed = FATALERR; 5281553Srgrimes break; 5291553Srgrimes case REPRINT: 5301553Srgrimes (void) fclose(cfp); 5311553Srgrimes return(REPRINT); 5321553Srgrimes case FILTERERR: 5331553Srgrimes case ACCESS: 5341553Srgrimes bombed = i; 53531492Swollman sendmail(pp, logname, bombed); 5361553Srgrimes } 5371553Srgrimes title[0] = '\0'; 5381553Srgrimes continue; 5391553Srgrimes 5401553Srgrimes case 'N': 5411553Srgrimes case 'U': 5421553Srgrimes case 'M': 54315648Sjoerg case 'R': 5441553Srgrimes continue; 5451553Srgrimes } 5461553Srgrimes 5471553Srgrimes /* pass 2 */ 5481553Srgrimes 5491553Srgrimespass2: 5501553Srgrimes fseek(cfp, 0L, 0); 5511553Srgrimes while (getline(cfp)) 5521553Srgrimes switch (line[0]) { 5531553Srgrimes case 'L': /* identification line */ 55431492Swollman if (!pp->no_header && pp->header_last) 55531492Swollman banner(pp, line+1, jobname); 5561553Srgrimes continue; 5571553Srgrimes 5581553Srgrimes case 'M': 5591553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 56031492Swollman sendmail(pp, line+1, bombed); 5611553Srgrimes continue; 5621553Srgrimes 5631553Srgrimes case 'U': 56427748Simp if (strchr(line+1, '/')) 56527748Simp continue; 5661553Srgrimes (void) unlink(line+1); 5671553Srgrimes } 5681553Srgrimes /* 5691553Srgrimes * clean-up in case another control file exists 5701553Srgrimes */ 5711553Srgrimes (void) fclose(cfp); 5721553Srgrimes (void) unlink(file); 5731553Srgrimes return(bombed == OK ? OK : ERROR); 5741553Srgrimes} 5751553Srgrimes 5761553Srgrimes/* 5771553Srgrimes * Print a file. 5781553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 5791553Srgrimes * Return -1 if a non-recoverable error occured, 5801553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 5811553Srgrimes * 1 if we should try to reprint this job and 5821553Srgrimes * 0 if all is well. 5831553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5841553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5851553Srgrimes */ 5861553Srgrimesstatic int 58731492Swollmanprint(pp, format, file) 58831492Swollman struct printer *pp; 5891553Srgrimes int format; 5901553Srgrimes char *file; 5911553Srgrimes{ 59253956Sache register int n, i; 5931553Srgrimes register char *prog; 59431492Swollman int fi, fo; 5951553Srgrimes FILE *fp; 5961553Srgrimes char *av[15], buf[BUFSIZ]; 59768734Sgad int pid, p[2], stopped; 5981553Srgrimes union wait status; 5991553Srgrimes struct stat stb; 6001553Srgrimes 60168467Sgad if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 60268467Sgad syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 60368467Sgad pp->printer, file, format); 6041553Srgrimes return(ERROR); 60568467Sgad } 6061553Srgrimes /* 6071553Srgrimes * Check to see if data file is a symbolic link. If so, it should 6081553Srgrimes * still point to the same file or someone is trying to print 6091553Srgrimes * something he shouldn't. 6101553Srgrimes */ 6111553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 6121553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 6131553Srgrimes return(ACCESS); 61468253Sgad 61568253Sgad job_dfcnt++; /* increment datafile counter for this job */ 61668734Sgad stopped = 0; /* output filter is not stopped */ 61768253Sgad 61868253Sgad /* everything seems OK, start it up */ 61931492Swollman if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 62031492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 62131492Swollman pp->tof = 1; 6221553Srgrimes } 62331492Swollman if (pp->filters[LPF_INPUT] == NULL 62431492Swollman && (format == 'f' || format == 'l')) { 62531492Swollman pp->tof = 0; 6261553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 6271553Srgrimes if (write(ofd, buf, n) != n) { 6281553Srgrimes (void) close(fi); 6291553Srgrimes return(REPRINT); 6301553Srgrimes } 6311553Srgrimes (void) close(fi); 6321553Srgrimes return(OK); 6331553Srgrimes } 6341553Srgrimes switch (format) { 6351553Srgrimes case 'p': /* print file using 'pr' */ 63631492Swollman if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 6371553Srgrimes prog = _PATH_PR; 63853956Sache i = 0; 63953956Sache av[i++] = "pr"; 64053956Sache av[i++] = width; 64153956Sache av[i++] = length; 64253956Sache av[i++] = "-h"; 64353956Sache av[i++] = *title ? title : " "; 64453956Sache av[i++] = "-L"; 64553956Sache av[i++] = *locale ? locale : "C"; 64653956Sache av[i++] = "-F"; 64753956Sache av[i] = 0; 6481553Srgrimes fo = ofd; 6491553Srgrimes goto start; 6501553Srgrimes } 6511553Srgrimes pipe(p); 65231492Swollman if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 6531553Srgrimes dup2(fi, 0); /* file is stdin */ 6541553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 6558094Sjkh closelog(); 65631492Swollman closeallfds(3); 6571553Srgrimes execl(_PATH_PR, "pr", width, length, 65853956Sache "-h", *title ? title : " ", 65953956Sache "-L", *locale ? locale : "C", 66053956Sache "-F", 0); 6611553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 6621553Srgrimes exit(2); 6631553Srgrimes } 6641553Srgrimes (void) close(p[1]); /* close output side */ 6651553Srgrimes (void) close(fi); 6661553Srgrimes if (prchild < 0) { 6671553Srgrimes prchild = 0; 6681553Srgrimes (void) close(p[0]); 6691553Srgrimes return(ERROR); 6701553Srgrimes } 6711553Srgrimes fi = p[0]; /* use pipe for input */ 6721553Srgrimes case 'f': /* print plain text file */ 67331492Swollman prog = pp->filters[LPF_INPUT]; 6741553Srgrimes av[1] = width; 6751553Srgrimes av[2] = length; 6761553Srgrimes av[3] = indent; 6771553Srgrimes n = 4; 6781553Srgrimes break; 6791553Srgrimes case 'l': /* like 'f' but pass control characters */ 68031492Swollman prog = pp->filters[LPF_INPUT]; 6811553Srgrimes av[1] = "-c"; 6821553Srgrimes av[2] = width; 6831553Srgrimes av[3] = length; 6841553Srgrimes av[4] = indent; 6851553Srgrimes n = 5; 6861553Srgrimes break; 6871553Srgrimes case 'r': /* print a fortran text file */ 68831492Swollman prog = pp->filters[LPF_FORTRAN]; 6891553Srgrimes av[1] = width; 6901553Srgrimes av[2] = length; 6911553Srgrimes n = 3; 6921553Srgrimes break; 6931553Srgrimes case 't': /* print troff output */ 6941553Srgrimes case 'n': /* print ditroff output */ 6951553Srgrimes case 'd': /* print tex output */ 6961553Srgrimes (void) unlink(".railmag"); 6971553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 69831492Swollman syslog(LOG_ERR, "%s: cannot create .railmag", 69931492Swollman pp->printer); 7001553Srgrimes (void) unlink(".railmag"); 7011553Srgrimes } else { 7021553Srgrimes for (n = 0; n < 4; n++) { 7031553Srgrimes if (fonts[n][0] != '/') 7041553Srgrimes (void) write(fo, _PATH_VFONT, 7051553Srgrimes sizeof(_PATH_VFONT) - 1); 7061553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 7071553Srgrimes (void) write(fo, "\n", 1); 7081553Srgrimes } 7091553Srgrimes (void) close(fo); 7101553Srgrimes } 71131492Swollman prog = (format == 't') ? pp->filters[LPF_TROFF] 71231492Swollman : ((format == 'n') ? pp->filters[LPF_DITROFF] 71331492Swollman : pp->filters[LPF_DVI]); 7141553Srgrimes av[1] = pxwidth; 7151553Srgrimes av[2] = pxlength; 7161553Srgrimes n = 3; 7171553Srgrimes break; 7181553Srgrimes case 'c': /* print cifplot output */ 71931492Swollman prog = pp->filters[LPF_CIFPLOT]; 7201553Srgrimes av[1] = pxwidth; 7211553Srgrimes av[2] = pxlength; 7221553Srgrimes n = 3; 7231553Srgrimes break; 7241553Srgrimes case 'g': /* print plot(1G) output */ 72531492Swollman prog = pp->filters[LPF_GRAPH]; 7261553Srgrimes av[1] = pxwidth; 7271553Srgrimes av[2] = pxlength; 7281553Srgrimes n = 3; 7291553Srgrimes break; 7301553Srgrimes case 'v': /* print raster output */ 73131492Swollman prog = pp->filters[LPF_RASTER]; 7321553Srgrimes av[1] = pxwidth; 7331553Srgrimes av[2] = pxlength; 7341553Srgrimes n = 3; 7351553Srgrimes break; 7361553Srgrimes default: 7371553Srgrimes (void) close(fi); 7381553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 73931492Swollman pp->printer, format); 7401553Srgrimes return(ERROR); 7411553Srgrimes } 74215648Sjoerg if (prog == NULL) { 74315648Sjoerg (void) close(fi); 74415648Sjoerg syslog(LOG_ERR, 74515648Sjoerg "%s: no filter found in printcap for format character '%c'", 74631492Swollman pp->printer, format); 74715648Sjoerg return(ERROR); 74815648Sjoerg } 74927635Simp if ((av[0] = strrchr(prog, '/')) != NULL) 7501553Srgrimes av[0]++; 7511553Srgrimes else 7521553Srgrimes av[0] = prog; 7531553Srgrimes av[n++] = "-n"; 7541553Srgrimes av[n++] = logname; 7551553Srgrimes av[n++] = "-h"; 7561553Srgrimes av[n++] = fromhost; 75731492Swollman av[n++] = pp->acct_file; 7581553Srgrimes av[n] = 0; 7591553Srgrimes fo = pfd; 7601553Srgrimes if (ofilter > 0) { /* stop output filter */ 7611553Srgrimes write(ofd, "\031\1", 2); 7621553Srgrimes while ((pid = 7631553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 7641553Srgrimes ; 7651553Srgrimes if (status.w_stopval != WSTOPPED) { 7661553Srgrimes (void) close(fi); 76715648Sjoerg syslog(LOG_WARNING, 76831492Swollman "%s: output filter died " 76931492Swollman "(retcode=%d termsig=%d)", 77031492Swollman pp->printer, status.w_retcode, 77131492Swollman status.w_termsig); 7721553Srgrimes return(REPRINT); 7731553Srgrimes } 7741553Srgrimes stopped++; 7751553Srgrimes } 7761553Srgrimesstart: 77731492Swollman if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 7781553Srgrimes dup2(fi, 0); 7791553Srgrimes dup2(fo, 1); 78068664Sgad /* setup stderr for the filter (child process) 78168664Sgad * so it goes to our temporary errors file */ 78268664Sgad n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 7831553Srgrimes if (n >= 0) 7841553Srgrimes dup2(n, 2); 7858094Sjkh closelog(); 78631492Swollman closeallfds(3); 7871553Srgrimes execv(prog, av); 7881553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 7891553Srgrimes exit(2); 7901553Srgrimes } 7911553Srgrimes (void) close(fi); 7921553Srgrimes if (child < 0) 7931553Srgrimes status.w_retcode = 100; 7941553Srgrimes else 7951553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 7961553Srgrimes ; 7971553Srgrimes child = 0; 7981553Srgrimes prchild = 0; 7991553Srgrimes if (stopped) { /* restart output filter */ 8001553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 8011553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 8021553Srgrimes exit(1); 8031553Srgrimes } 8041553Srgrimes } 80531492Swollman pp->tof = 0; 8061553Srgrimes 80768664Sgad /* Copy the filter's output to "lf" logfile */ 80868664Sgad if ((fp = fopen(tempstderr, "r"))) { 8091553Srgrimes while (fgets(buf, sizeof(buf), fp)) 8101553Srgrimes fputs(buf, stderr); 8111553Srgrimes fclose(fp); 8121553Srgrimes } 8131553Srgrimes 8141553Srgrimes if (!WIFEXITED(status)) { 81515648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 81631492Swollman pp->printer, format, status.w_termsig); 8171553Srgrimes return(ERROR); 8181553Srgrimes } 8191553Srgrimes switch (status.w_retcode) { 8201553Srgrimes case 0: 82131492Swollman pp->tof = 1; 8221553Srgrimes return(OK); 8231553Srgrimes case 1: 8241553Srgrimes return(REPRINT); 82515648Sjoerg case 2: 82615648Sjoerg return(ERROR); 8271553Srgrimes default: 82815648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 82931492Swollman pp->printer, format, status.w_retcode); 83015648Sjoerg return(FILTERERR); 8311553Srgrimes } 8321553Srgrimes} 8331553Srgrimes 8341553Srgrimes/* 8351553Srgrimes * Send the daemon control file (cf) and any data files. 8361553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 8371553Srgrimes * 0 if all is well. 8381553Srgrimes */ 8391553Srgrimesstatic int 84031492Swollmansendit(pp, file) 84131492Swollman struct printer *pp; 8421553Srgrimes char *file; 8431553Srgrimes{ 8441553Srgrimes register int i, err = OK; 8451553Srgrimes char *cp, last[BUFSIZ]; 8461553Srgrimes 8471553Srgrimes /* 8481553Srgrimes * open control file 8491553Srgrimes */ 8501553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 8511553Srgrimes return(OK); 85268253Sgad 85368253Sgad /* initialize job-specific count of datafiles processed */ 85468253Sgad job_dfcnt = 0; 85568253Sgad 8561553Srgrimes /* 8571553Srgrimes * read the control file for work to do 8581553Srgrimes * 8591553Srgrimes * file format -- first character in the line is a command 8601553Srgrimes * rest of the line is the argument. 8611553Srgrimes * commands of interest are: 8621553Srgrimes * 8631553Srgrimes * a-z -- "file name" name of file to print 8641553Srgrimes * U -- "unlink" name of file to remove 8651553Srgrimes * (after we print it. (Pass 2 only)). 8661553Srgrimes */ 8671553Srgrimes 8681553Srgrimes /* 8691553Srgrimes * pass 1 8701553Srgrimes */ 8711553Srgrimes while (getline(cfp)) { 8721553Srgrimes again: 8731553Srgrimes if (line[0] == 'S') { 8741553Srgrimes cp = line+1; 8751553Srgrimes i = 0; 8761553Srgrimes while (*cp >= '0' && *cp <= '9') 8771553Srgrimes i = i * 10 + (*cp++ - '0'); 8781553Srgrimes fdev = i; 8791553Srgrimes cp++; 8801553Srgrimes i = 0; 8811553Srgrimes while (*cp >= '0' && *cp <= '9') 8821553Srgrimes i = i * 10 + (*cp++ - '0'); 8831553Srgrimes fino = i; 88424831Sbrian } else if (line[0] == 'H') { 88568343Sgad strncpy(fromhost, line+1, sizeof(fromhost) - 1); 88668343Sgad fromhost[sizeof(fromhost) - 1] = '\0'; 88768343Sgad if (class[0] == '\0') { 88827748Simp strncpy(class, line+1, sizeof(class) - 1); 88968343Sgad class[sizeof(class) - 1] = '\0'; 89068343Sgad } 89124831Sbrian } else if (line[0] == 'P') { 89227748Simp strncpy(logname, line+1, sizeof(logname) - 1); 89368741Sgad logname[sizeof(logname) - 1] = '\0'; 89431492Swollman if (pp->restricted) { /* restricted */ 89524831Sbrian if (getpwnam(logname) == NULL) { 89631492Swollman sendmail(pp, line+1, NOACCT); 89724831Sbrian err = ERROR; 89824831Sbrian break; 89924831Sbrian } 90024831Sbrian } 90124831Sbrian } else if (line[0] == 'I') { 90227748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 90368741Sgad indent[2 + sizeof(indent) - 3] = '\0'; 90424831Sbrian } else if (line[0] >= 'a' && line[0] <= 'z') { 9051553Srgrimes strcpy(last, line); 90631492Swollman while ((i = getline(cfp)) != 0) 9071553Srgrimes if (strcmp(last, line)) 9081553Srgrimes break; 90931492Swollman switch (sendfile(pp, '\3', last+1, *last)) { 9101553Srgrimes case OK: 9111553Srgrimes if (i) 9121553Srgrimes goto again; 9131553Srgrimes break; 9141553Srgrimes case REPRINT: 9151553Srgrimes (void) fclose(cfp); 9161553Srgrimes return(REPRINT); 9171553Srgrimes case ACCESS: 91831492Swollman sendmail(pp, logname, ACCESS); 9191553Srgrimes case ERROR: 9201553Srgrimes err = ERROR; 9211553Srgrimes } 9221553Srgrimes break; 9231553Srgrimes } 9241553Srgrimes } 92531492Swollman if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 9261553Srgrimes (void) fclose(cfp); 9271553Srgrimes return(REPRINT); 9281553Srgrimes } 9291553Srgrimes /* 9301553Srgrimes * pass 2 9311553Srgrimes */ 9321553Srgrimes fseek(cfp, 0L, 0); 9331553Srgrimes while (getline(cfp)) 93427748Simp if (line[0] == 'U' && !strchr(line+1, '/')) 9351553Srgrimes (void) unlink(line+1); 9361553Srgrimes /* 9371553Srgrimes * clean-up in case another control file exists 9381553Srgrimes */ 9391553Srgrimes (void) fclose(cfp); 9401553Srgrimes (void) unlink(file); 9411553Srgrimes return(err); 9421553Srgrimes} 9431553Srgrimes 9441553Srgrimes/* 9451553Srgrimes * Send a data file to the remote machine and spool it. 9461553Srgrimes * Return positive if we should try resending. 9471553Srgrimes */ 9481553Srgrimesstatic int 94931492Swollmansendfile(pp, type, file, format) 95031492Swollman struct printer *pp; 9511553Srgrimes int type; 9521553Srgrimes char *file; 95324831Sbrian char format; 9541553Srgrimes{ 9551553Srgrimes register int f, i, amt; 9561553Srgrimes struct stat stb; 95768664Sgad FILE *fp; 9581553Srgrimes char buf[BUFSIZ]; 95974124Sgad int closedpr, resp, sizerr, statrc; 9601553Srgrimes 96174124Sgad statrc = lstat(file, &stb); 96274124Sgad if (statrc < 0) { 96374124Sgad syslog(LOG_ERR, "%s: error from lstat(%s): %m", 96474124Sgad pp->printer, file); 9651553Srgrimes return(ERROR); 96674124Sgad } 96774124Sgad f = open(file, O_RDONLY); 96874124Sgad if (f < 0) { 96974124Sgad syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 97074124Sgad pp->printer, file); 97174124Sgad return(ERROR); 97274124Sgad } 9731553Srgrimes /* 9741553Srgrimes * Check to see if data file is a symbolic link. If so, it should 9751553Srgrimes * still point to the same file or someone is trying to print something 9761553Srgrimes * he shouldn't. 9771553Srgrimes */ 9781553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 9791553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 9801553Srgrimes return(ACCESS); 98124831Sbrian 98268253Sgad job_dfcnt++; /* increment datafile counter for this job */ 98368253Sgad 98468253Sgad /* everything seems OK, start it up */ 98524831Sbrian sizerr = 0; 98624831Sbrian closedpr = 0; 98724831Sbrian if (type == '\3') { 98831492Swollman if (pp->filters[LPF_INPUT]) { 98924831Sbrian /* 99074124Sgad * We're sending something with an ifilter. We have to 99174124Sgad * run the ifilter and store the output as a temporary 99274124Sgad * spool file (tfile...), because the protocol requires 99374124Sgad * us to send the file size before we start sending any 99474124Sgad * of the data. 99524831Sbrian */ 99624831Sbrian char *av[15]; 99724831Sbrian int n; 99824831Sbrian int ifilter; 99931492Swollman union wait status; /* XXX */ 100024831Sbrian 100124831Sbrian strcpy(tfile,TFILENAME); 100224831Sbrian if ((tfd = mkstemp(tfile)) == -1) { 100324831Sbrian syslog(LOG_ERR, "mkstemp: %m"); 100424831Sbrian return(ERROR); 100524831Sbrian } 100631492Swollman if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 100731492Swollman av[0] = pp->filters[LPF_INPUT]; 100824831Sbrian else 100924831Sbrian av[0]++; 101024831Sbrian if (format == 'l') 101124831Sbrian av[n=1] = "-c"; 101224831Sbrian else 101324831Sbrian n = 0; 101424831Sbrian av[++n] = width; 101524831Sbrian av[++n] = length; 101624831Sbrian av[++n] = indent; 101724831Sbrian av[++n] = "-n"; 101824831Sbrian av[++n] = logname; 101924831Sbrian av[++n] = "-h"; 102024831Sbrian av[++n] = fromhost; 102131492Swollman av[++n] = pp->acct_file; 102224831Sbrian av[++n] = 0; 102331492Swollman if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 102424831Sbrian dup2(f, 0); 102524831Sbrian dup2(tfd, 1); 102668664Sgad /* setup stderr for the filter (child process) 102768664Sgad * so it goes to our temporary errors file */ 102868664Sgad n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 102924831Sbrian if (n >= 0) 103024831Sbrian dup2(n, 2); 103124831Sbrian closelog(); 103231492Swollman closeallfds(3); 103331492Swollman execv(pp->filters[LPF_INPUT], av); 103431492Swollman syslog(LOG_ERR, "cannot execv %s", 103531492Swollman pp->filters[LPF_INPUT]); 103624831Sbrian exit(2); 103724831Sbrian } 103824831Sbrian (void) close(f); 103924831Sbrian if (ifilter < 0) 104024831Sbrian status.w_retcode = 100; 104124831Sbrian else 104224831Sbrian while ((pid = wait((int *)&status)) > 0 && 104324831Sbrian pid != ifilter) 104424831Sbrian ; 104568664Sgad /* Copy the filter's output to "lf" logfile */ 104668664Sgad if ((fp = fopen(tempstderr, "r"))) { 104768664Sgad while (fgets(buf, sizeof(buf), fp)) 104868664Sgad fputs(buf, stderr); 104968664Sgad fclose(fp); 105068664Sgad } 105168664Sgad /* process the return-code from the filter */ 105224831Sbrian switch (status.w_retcode) { 105324831Sbrian case 0: 105424831Sbrian break; 105524831Sbrian case 1: 105624831Sbrian unlink(tfile); 105724831Sbrian return(REPRINT); 105824831Sbrian case 2: 105924831Sbrian unlink(tfile); 106024831Sbrian return(ERROR); 106124831Sbrian default: 106224831Sbrian syslog(LOG_WARNING, "%s: filter '%c' exited" 106324831Sbrian " (retcode=%d)", 106431492Swollman pp->printer, format, status.w_retcode); 106524831Sbrian unlink(tfile); 106624831Sbrian return(FILTERERR); 106724831Sbrian } 106874124Sgad statrc = fstat(tfd, &stb); /* to find size of tfile */ 106974124Sgad if (statrc < 0) { 107074124Sgad syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m", 107174124Sgad pp->printer, tfile); 107224831Sbrian return(ERROR); 107374124Sgad } 107424831Sbrian f = tfd; 107524831Sbrian lseek(f,0,SEEK_SET); 107624831Sbrian } else if (ofilter) { 107724831Sbrian /* 107824831Sbrian * We're sending something with an ofilter, we have to 107924831Sbrian * store the output as a temporary file (tfile)... the 108024831Sbrian * protocol requires us to send the file size 108124831Sbrian */ 108224831Sbrian int i; 108324831Sbrian for (i = 0; i < stb.st_size; i += BUFSIZ) { 108424831Sbrian amt = BUFSIZ; 108524831Sbrian if (i + amt > stb.st_size) 108624831Sbrian amt = stb.st_size - i; 108724831Sbrian if (sizerr == 0 && read(f, buf, amt) != amt) { 108824831Sbrian sizerr = 1; 108924831Sbrian break; 109024831Sbrian } 109124831Sbrian if (write(ofd, buf, amt) != amt) { 109224831Sbrian (void) close(f); 109324831Sbrian return(REPRINT); 109424831Sbrian } 109524831Sbrian } 109624831Sbrian close(ofd); 109724831Sbrian close(f); 109824831Sbrian while ((i = wait(NULL)) > 0 && i != ofilter) 109924831Sbrian ; 110024831Sbrian ofilter = 0; 110174124Sgad statrc = fstat(tfd, &stb); /* to find size of tfile */ 110274124Sgad if (statrc < 0) { 110374124Sgad syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m", 110474124Sgad pp->printer, tfile); 110531492Swollman openpr(pp); 110624831Sbrian return(ERROR); 110724831Sbrian } 110824831Sbrian f = tfd; 110924831Sbrian lseek(f,0,SEEK_SET); 111024831Sbrian closedpr = 1; 111124831Sbrian } 111224831Sbrian } 111324831Sbrian 11141553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 11151553Srgrimes amt = strlen(buf); 11161553Srgrimes for (i = 0; ; i++) { 11171553Srgrimes if (write(pfd, buf, amt) != amt || 111831492Swollman (resp = response(pp)) < 0 || resp == '\1') { 11191553Srgrimes (void) close(f); 112024831Sbrian if (tfd != -1 && type == '\3') { 112124831Sbrian tfd = -1; 112224831Sbrian unlink(tfile); 112324831Sbrian if (closedpr) 112431492Swollman openpr(pp); 112524831Sbrian } 11261553Srgrimes return(REPRINT); 11271553Srgrimes } else if (resp == '\0') 11281553Srgrimes break; 11291553Srgrimes if (i == 0) 113031492Swollman pstatus(pp, 113131492Swollman "no space on remote; waiting for queue to drain"); 11321553Srgrimes if (i == 10) 11331553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 113431492Swollman pp->printer, pp->remote_host); 11351553Srgrimes sleep(5 * 60); 11361553Srgrimes } 11371553Srgrimes if (i) 113831492Swollman pstatus(pp, "sending to %s", pp->remote_host); 113968253Sgad if (type == '\3') 114068253Sgad trstat_init(pp, file, job_dfcnt); 11411553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 11421553Srgrimes amt = BUFSIZ; 11431553Srgrimes if (i + amt > stb.st_size) 11441553Srgrimes amt = stb.st_size - i; 11451553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 11461553Srgrimes sizerr = 1; 11471553Srgrimes if (write(pfd, buf, amt) != amt) { 11481553Srgrimes (void) close(f); 114924831Sbrian if (tfd != -1 && type == '\3') { 115024831Sbrian tfd = -1; 115124831Sbrian unlink(tfile); 115224831Sbrian if (closedpr) 115331492Swollman openpr(pp); 115424831Sbrian } 11551553Srgrimes return(REPRINT); 11561553Srgrimes } 11571553Srgrimes } 11581553Srgrimes 11591553Srgrimes (void) close(f); 116024831Sbrian if (tfd != -1 && type == '\3') { 116124831Sbrian tfd = -1; 116224831Sbrian unlink(tfile); 116324831Sbrian } 11641553Srgrimes if (sizerr) { 116531492Swollman syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 11661553Srgrimes /* tell recvjob to ignore this file */ 11671553Srgrimes (void) write(pfd, "\1", 1); 116824831Sbrian if (closedpr) 116931492Swollman openpr(pp); 11701553Srgrimes return(ERROR); 11711553Srgrimes } 117231492Swollman if (write(pfd, "", 1) != 1 || response(pp)) { 117324831Sbrian if (closedpr) 117431492Swollman openpr(pp); 11751553Srgrimes return(REPRINT); 117624831Sbrian } 117724831Sbrian if (closedpr) 117831492Swollman openpr(pp); 117968253Sgad if (type == '\3') 118068253Sgad trstat_write(pp, TR_SENDING, stb.st_size, logname, 118168253Sgad pp->remote_host, fromhost); 11821553Srgrimes return(OK); 11831553Srgrimes} 11841553Srgrimes 11851553Srgrimes/* 11861553Srgrimes * Check to make sure there have been no errors and that both programs 11871553Srgrimes * are in sync with eachother. 11881553Srgrimes * Return non-zero if the connection was lost. 11891553Srgrimes */ 11901553Srgrimesstatic char 119131492Swollmanresponse(pp) 119231492Swollman const struct printer *pp; 11931553Srgrimes{ 11941553Srgrimes char resp; 11951553Srgrimes 11961553Srgrimes if (read(pfd, &resp, 1) != 1) { 119731492Swollman syslog(LOG_INFO, "%s: lost connection", pp->printer); 11981553Srgrimes return(-1); 11991553Srgrimes } 12001553Srgrimes return(resp); 12011553Srgrimes} 12021553Srgrimes 12031553Srgrimes/* 12041553Srgrimes * Banner printing stuff 12051553Srgrimes */ 12061553Srgrimesstatic void 120731492Swollmanbanner(pp, name1, name2) 120831492Swollman struct printer *pp; 12091553Srgrimes char *name1, *name2; 12101553Srgrimes{ 12111553Srgrimes time_t tvec; 12121553Srgrimes 12131553Srgrimes time(&tvec); 121431492Swollman if (!pp->no_formfeed && !pp->tof) 121531492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 121631492Swollman if (pp->short_banner) { /* short banner only */ 12171553Srgrimes if (class[0]) { 12181553Srgrimes (void) write(ofd, class, strlen(class)); 12191553Srgrimes (void) write(ofd, ":", 1); 12201553Srgrimes } 12211553Srgrimes (void) write(ofd, name1, strlen(name1)); 12221553Srgrimes (void) write(ofd, " Job: ", 7); 12231553Srgrimes (void) write(ofd, name2, strlen(name2)); 12241553Srgrimes (void) write(ofd, " Date: ", 8); 12251553Srgrimes (void) write(ofd, ctime(&tvec), 24); 12261553Srgrimes (void) write(ofd, "\n", 1); 12271553Srgrimes } else { /* normal banner */ 12281553Srgrimes (void) write(ofd, "\n\n\n", 3); 122931492Swollman scan_out(pp, ofd, name1, '\0'); 12301553Srgrimes (void) write(ofd, "\n\n", 2); 123131492Swollman scan_out(pp, ofd, name2, '\0'); 12321553Srgrimes if (class[0]) { 12331553Srgrimes (void) write(ofd,"\n\n\n",3); 123431492Swollman scan_out(pp, ofd, class, '\0'); 12351553Srgrimes } 12361553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 12371553Srgrimes (void) write(ofd, name2, strlen(name2)); 12381553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 12391553Srgrimes (void) write(ofd, ctime(&tvec), 24); 12401553Srgrimes (void) write(ofd, "\n", 1); 12411553Srgrimes } 124231492Swollman if (!pp->no_formfeed) 124331492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 124431492Swollman pp->tof = 1; 12451553Srgrimes} 12461553Srgrimes 12471553Srgrimesstatic char * 12481553Srgrimesscnline(key, p, c) 12491553Srgrimes register int key; 12501553Srgrimes register char *p; 12511553Srgrimes int c; 12521553Srgrimes{ 125339084Swollman register int scnwidth; 12541553Srgrimes 12551553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 12561553Srgrimes key <<= 1; 12571553Srgrimes *p++ = key & 0200 ? c : BACKGND; 12581553Srgrimes } 12591553Srgrimes return (p); 12601553Srgrimes} 12611553Srgrimes 12621553Srgrimes#define TRC(q) (((q)-' ')&0177) 12631553Srgrimes 12641553Srgrimesstatic void 126531492Swollmanscan_out(pp, scfd, scsp, dlm) 126631492Swollman struct printer *pp; 12671553Srgrimes int scfd, dlm; 12681553Srgrimes char *scsp; 12691553Srgrimes{ 12701553Srgrimes register char *strp; 127139084Swollman register int nchrs, j; 12721553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 12731553Srgrimes int d, scnhgt; 12741553Srgrimes 12751553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 12761553Srgrimes strp = &outbuf[0]; 12771553Srgrimes sp = scsp; 12781553Srgrimes for (nchrs = 0; ; ) { 12791553Srgrimes d = dropit(c = TRC(cc = *sp++)); 12801553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 12811553Srgrimes for (j = WIDTH; --j;) 12821553Srgrimes *strp++ = BACKGND; 12831553Srgrimes else 128431492Swollman strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 128531492Swollman if (*sp == dlm || *sp == '\0' || 128631492Swollman nchrs++ >= pp->page_width/(WIDTH+1)-1) 12871553Srgrimes break; 12881553Srgrimes *strp++ = BACKGND; 12891553Srgrimes *strp++ = BACKGND; 12901553Srgrimes } 12911553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 12921553Srgrimes ; 12931553Srgrimes strp++; 12948857Srgrimes *strp++ = '\n'; 12951553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 12961553Srgrimes } 12971553Srgrimes} 12981553Srgrimes 12991553Srgrimesstatic int 13001553Srgrimesdropit(c) 13011553Srgrimes int c; 13021553Srgrimes{ 13031553Srgrimes switch(c) { 13041553Srgrimes 13051553Srgrimes case TRC('_'): 13061553Srgrimes case TRC(';'): 13071553Srgrimes case TRC(','): 13081553Srgrimes case TRC('g'): 13091553Srgrimes case TRC('j'): 13101553Srgrimes case TRC('p'): 13111553Srgrimes case TRC('q'): 13121553Srgrimes case TRC('y'): 13131553Srgrimes return (DROP); 13141553Srgrimes 13151553Srgrimes default: 13161553Srgrimes return (0); 13171553Srgrimes } 13181553Srgrimes} 13191553Srgrimes 13201553Srgrimes/* 13211553Srgrimes * sendmail --- 13221553Srgrimes * tell people about job completion 13231553Srgrimes */ 13241553Srgrimesstatic void 132531492Swollmansendmail(pp, user, bombed) 132631492Swollman struct printer *pp; 13271553Srgrimes char *user; 13281553Srgrimes int bombed; 13291553Srgrimes{ 13301553Srgrimes register int i; 13311553Srgrimes int p[2], s; 13321553Srgrimes register char *cp; 13331553Srgrimes struct stat stb; 13341553Srgrimes FILE *fp; 13351553Srgrimes 13361553Srgrimes pipe(p); 133731492Swollman if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 13381553Srgrimes dup2(p[0], 0); 13398094Sjkh closelog(); 134031492Swollman closeallfds(3); 134127635Simp if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 13421553Srgrimes cp++; 134331492Swollman else 13441553Srgrimes cp = _PATH_SENDMAIL; 134527757Simp execl(_PATH_SENDMAIL, cp, "-t", 0); 134631492Swollman _exit(0); 13471553Srgrimes } else if (s > 0) { /* parent */ 13481553Srgrimes dup2(p[1], 1); 13491553Srgrimes printf("To: %s@%s\n", user, fromhost); 135031492Swollman printf("Subject: %s printer job \"%s\"\n", pp->printer, 135115648Sjoerg *jobname ? jobname : "<unknown>"); 135215648Sjoerg printf("Reply-To: root@%s\n\n", host); 13531553Srgrimes printf("Your printer job "); 13541553Srgrimes if (*jobname) 13551553Srgrimes printf("(%s) ", jobname); 135631492Swollman 135731492Swollman cp = "XXX compiler confusion"; /* XXX shut GCC up */ 13581553Srgrimes switch (bombed) { 13591553Srgrimes case OK: 13601553Srgrimes printf("\ncompleted successfully\n"); 136115648Sjoerg cp = "OK"; 13621553Srgrimes break; 13631553Srgrimes default: 13641553Srgrimes case FATALERR: 13651553Srgrimes printf("\ncould not be printed\n"); 136615648Sjoerg cp = "FATALERR"; 13671553Srgrimes break; 13681553Srgrimes case NOACCT: 13691553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 137015648Sjoerg cp = "NOACCT"; 13711553Srgrimes break; 13721553Srgrimes case FILTERERR: 137368664Sgad if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 137468664Sgad || (fp = fopen(tempstderr, "r")) == NULL) { 137515648Sjoerg printf("\nhad some errors and may not have printed\n"); 13761553Srgrimes break; 13771553Srgrimes } 137815648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 13791553Srgrimes while ((i = getc(fp)) != EOF) 13801553Srgrimes putchar(i); 13811553Srgrimes (void) fclose(fp); 138215648Sjoerg cp = "FILTERERR"; 13831553Srgrimes break; 13841553Srgrimes case ACCESS: 13851553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 138615648Sjoerg cp = "ACCESS"; 13871553Srgrimes } 13881553Srgrimes fflush(stdout); 13891553Srgrimes (void) close(1); 139031492Swollman } else { 139131492Swollman syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 139231492Swollman return; 13931553Srgrimes } 13941553Srgrimes (void) close(p[0]); 13951553Srgrimes (void) close(p[1]); 139615648Sjoerg wait(NULL); 139715648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 139831492Swollman user, *jobname ? jobname : "<unknown>", pp->printer, cp); 13991553Srgrimes} 14001553Srgrimes 14011553Srgrimes/* 14021553Srgrimes * dofork - fork with retries on failure 14031553Srgrimes */ 14041553Srgrimesstatic int 140531492Swollmandofork(pp, action) 140631492Swollman const struct printer *pp; 14071553Srgrimes int action; 14081553Srgrimes{ 14091553Srgrimes register int i, pid; 141060871Smpp struct passwd *pwd; 14111553Srgrimes 14121553Srgrimes for (i = 0; i < 20; i++) { 14131553Srgrimes if ((pid = fork()) < 0) { 14141553Srgrimes sleep((unsigned)(i*i)); 14151553Srgrimes continue; 14161553Srgrimes } 14171553Srgrimes /* 14181553Srgrimes * Child should run as daemon instead of root 14191553Srgrimes */ 142060871Smpp if (pid == 0) { 142160871Smpp if ((pwd = getpwuid(pp->daemon_user)) == NULL) { 142268379Sgad syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", 142360871Smpp pp->daemon_user); 142460871Smpp break; 142560871Smpp } 142660871Smpp initgroups(pwd->pw_name, pwd->pw_gid); 142760871Smpp setgid(pwd->pw_gid); 142831492Swollman setuid(pp->daemon_user); 142960871Smpp } 14301553Srgrimes return(pid); 14311553Srgrimes } 14321553Srgrimes syslog(LOG_ERR, "can't fork"); 14331553Srgrimes 14341553Srgrimes switch (action) { 14351553Srgrimes case DORETURN: 14361553Srgrimes return (-1); 14371553Srgrimes default: 14381553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 14391553Srgrimes /*FALL THRU*/ 14401553Srgrimes case DOABORT: 14411553Srgrimes exit(1); 14421553Srgrimes } 14431553Srgrimes /*NOTREACHED*/ 14441553Srgrimes} 14451553Srgrimes 14461553Srgrimes/* 14471553Srgrimes * Kill child processes to abort current job. 14481553Srgrimes */ 14491553Srgrimesstatic void 14501553Srgrimesabortpr(signo) 14511553Srgrimes int signo; 14521553Srgrimes{ 145368664Sgad 145468664Sgad (void) unlink(tempstderr); 14551553Srgrimes kill(0, SIGINT); 14561553Srgrimes if (ofilter > 0) 14571553Srgrimes kill(ofilter, SIGCONT); 14581553Srgrimes while (wait(NULL) > 0) 14591553Srgrimes ; 146024831Sbrian if (ofilter > 0 && tfd != -1) 146124831Sbrian unlink(tfile); 14621553Srgrimes exit(0); 14631553Srgrimes} 14641553Srgrimes 14651553Srgrimesstatic void 146631492Swollmaninit(pp) 146731492Swollman struct printer *pp; 14681553Srgrimes{ 14691553Srgrimes char *s; 14701553Srgrimes 147131492Swollman sprintf(&width[2], "%ld", pp->page_width); 147231492Swollman sprintf(&length[2], "%ld", pp->page_length); 147331492Swollman sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 147431492Swollman sprintf(&pxlength[2], "%ld", pp->page_plength); 147531492Swollman if ((s = checkremote(pp)) != 0) { 147631492Swollman syslog(LOG_WARNING, "%s", s); 147731492Swollman free(s); 147831492Swollman } 147931492Swollman} 148031492Swollman 148131492Swollmanvoid 148231492Swollmanstartprinting(printer) 148331492Swollman const char *printer; 148431492Swollman{ 148531492Swollman struct printer myprinter, *pp = &myprinter; 148631492Swollman int status; 148731492Swollman 148831492Swollman init_printer(pp); 148931492Swollman status = getprintcap(printer, pp); 149031492Swollman switch(status) { 149131492Swollman case PCAPERR_OSERR: 149231492Swollman syslog(LOG_ERR, "can't open printer description file: %m"); 14931553Srgrimes exit(1); 149431492Swollman case PCAPERR_NOTFOUND: 14951553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 14961553Srgrimes exit(1); 149731492Swollman case PCAPERR_TCLOOP: 149831492Swollman fatal(pp, "potential reference loop detected in printcap file"); 149931492Swollman default: 150031492Swollman break; 150131492Swollman } 150231492Swollman printjob(pp); 15031553Srgrimes} 15041553Srgrimes 15051553Srgrimes/* 15061553Srgrimes * Acquire line printer or remote connection. 15071553Srgrimes */ 15081553Srgrimesstatic void 150931492Swollmanopenpr(pp) 151031492Swollman const struct printer *pp; 15111553Srgrimes{ 151231492Swollman int p[2]; 151315648Sjoerg char *cp; 15141553Srgrimes 151531492Swollman if (pp->remote) { 151631492Swollman openrem(pp); 151731492Swollman } else if (*pp->lp) { 151831492Swollman if ((cp = strchr(pp->lp, '@')) != NULL) 151931492Swollman opennet(pp); 152015648Sjoerg else 152131492Swollman opentty(pp); 15221553Srgrimes } else { 15231553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 152431492Swollman pp->printer); 15251553Srgrimes exit(1); 15261553Srgrimes } 152715648Sjoerg 15281553Srgrimes /* 15291553Srgrimes * Start up an output filter, if needed. 15301553Srgrimes */ 153131492Swollman if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 15321553Srgrimes pipe(p); 153331492Swollman if (pp->remote) { 153431492Swollman strcpy(tfile, TFILENAME); 153524831Sbrian tfd = mkstemp(tfile); 153624831Sbrian } 153731492Swollman if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 15381553Srgrimes dup2(p[0], 0); /* pipe is std in */ 153924831Sbrian /* tfile/printer is stdout */ 154031492Swollman dup2(pp->remote ? tfd : pfd, 1); 15418094Sjkh closelog(); 154231492Swollman closeallfds(3); 154331492Swollman if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 154431492Swollman cp = pp->filters[LPF_OUTPUT]; 15451553Srgrimes else 15461553Srgrimes cp++; 154731492Swollman execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); 154831492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 154931492Swollman pp->filters[LPF_OUTPUT]); 15501553Srgrimes exit(1); 15511553Srgrimes } 15521553Srgrimes (void) close(p[0]); /* close input side */ 15531553Srgrimes ofd = p[1]; /* use pipe for output */ 15541553Srgrimes } else { 15551553Srgrimes ofd = pfd; 15561553Srgrimes ofilter = 0; 15571553Srgrimes } 15581553Srgrimes} 15591553Srgrimes 156015648Sjoerg/* 156115648Sjoerg * Printer connected directly to the network 156215648Sjoerg * or to a terminal server on the net 156315648Sjoerg */ 156415648Sjoergstatic void 156531492Swollmanopennet(pp) 156631492Swollman const struct printer *pp; 156715648Sjoerg{ 156815648Sjoerg register int i; 156931492Swollman int resp; 157031492Swollman u_long port; 157131492Swollman char *ep; 157230407Sjoerg void (*savealrm)(int); 157315648Sjoerg 157431492Swollman port = strtoul(pp->lp, &ep, 0); 157538470Sbrian if (*ep != '@' || port > 65535) { 157631492Swollman syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 157731492Swollman pp->lp); 157815648Sjoerg exit(1); 157915648Sjoerg } 158031492Swollman ep++; 158115648Sjoerg 158215648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 158315648Sjoerg resp = -1; 158430407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 158531492Swollman alarm(pp->conn_timeout); 158631492Swollman pfd = getport(pp, ep, port); 158731020Sjoerg alarm(0); 158830407Sjoerg (void)signal(SIGALRM, savealrm); 158915648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 159015648Sjoerg resp = 1; 159115648Sjoerg else if (pfd >= 0) { 159215648Sjoerg /* 159315648Sjoerg * need to delay a bit for rs232 lines 159415648Sjoerg * to stabilize in case printer is 159515648Sjoerg * connected via a terminal server 159615648Sjoerg */ 159715648Sjoerg delay(500); 159815648Sjoerg break; 159915648Sjoerg } 160015648Sjoerg if (i == 1) { 160131492Swollman if (resp < 0) 160231492Swollman pstatus(pp, "waiting for %s to come up", 160331492Swollman pp->lp); 160431492Swollman else 160531492Swollman pstatus(pp, 160631492Swollman "waiting for access to printer on %s", 160731492Swollman pp->lp); 160815648Sjoerg } 160915648Sjoerg sleep(i); 161015648Sjoerg } 161131492Swollman pstatus(pp, "sending to %s port %d", ep, port); 161215648Sjoerg} 161315648Sjoerg 161415648Sjoerg/* 161515648Sjoerg * Printer is connected to an RS232 port on this host 161615648Sjoerg */ 161715648Sjoergstatic void 161831492Swollmanopentty(pp) 161931492Swollman const struct printer *pp; 162015648Sjoerg{ 162115648Sjoerg register int i; 162215648Sjoerg 162315648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 162431492Swollman pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 162515648Sjoerg if (pfd >= 0) { 162615648Sjoerg delay(500); 162715648Sjoerg break; 162815648Sjoerg } 162915648Sjoerg if (errno == ENOENT) { 163031492Swollman syslog(LOG_ERR, "%s: %m", pp->lp); 163115648Sjoerg exit(1); 163215648Sjoerg } 163315648Sjoerg if (i == 1) 163431492Swollman pstatus(pp, 163531492Swollman "waiting for %s to become ready (offline?)", 163631492Swollman pp->printer); 163715648Sjoerg sleep(i); 163815648Sjoerg } 163915648Sjoerg if (isatty(pfd)) 164031492Swollman setty(pp); 164131492Swollman pstatus(pp, "%s is ready and printing", pp->printer); 164215648Sjoerg} 164315648Sjoerg 164415648Sjoerg/* 164515648Sjoerg * Printer is on a remote host 164615648Sjoerg */ 164715648Sjoergstatic void 164831492Swollmanopenrem(pp) 164931492Swollman const struct printer *pp; 165015648Sjoerg{ 165131492Swollman register int i; 165227748Simp int resp; 165330407Sjoerg void (*savealrm)(int); 165415648Sjoerg 165515648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 165615648Sjoerg resp = -1; 165730407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 165831492Swollman alarm(pp->conn_timeout); 165931492Swollman pfd = getport(pp, pp->remote_host, 0); 166031020Sjoerg alarm(0); 166130407Sjoerg (void)signal(SIGALRM, savealrm); 166215648Sjoerg if (pfd >= 0) { 166331492Swollman if ((writel(pfd, "\2", pp->remote_queue, "\n", 166431492Swollman (char *)0) 166531492Swollman == 2 + strlen(pp->remote_queue)) 166631492Swollman && (resp = response(pp)) == 0) 166715648Sjoerg break; 166815648Sjoerg (void) close(pfd); 166915648Sjoerg } 167015648Sjoerg if (i == 1) { 167115648Sjoerg if (resp < 0) 167231492Swollman pstatus(pp, "waiting for %s to come up", 167331492Swollman pp->remote_host); 167415648Sjoerg else { 167531492Swollman pstatus(pp, 167631492Swollman "waiting for queue to be enabled on %s", 167731492Swollman pp->remote_host); 167815648Sjoerg i = 256; 167915648Sjoerg } 168015648Sjoerg } 168115648Sjoerg sleep(i); 168215648Sjoerg } 168331492Swollman pstatus(pp, "sending to %s", pp->remote_host); 168415648Sjoerg} 168515648Sjoerg 16861553Srgrimes/* 16871553Srgrimes * setup tty lines. 16881553Srgrimes */ 16891553Srgrimesstatic void 169031492Swollmansetty(pp) 169131492Swollman const struct printer *pp; 16921553Srgrimes{ 169315032Ssef struct termios ttybuf; 16941553Srgrimes 16951553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 169631492Swollman syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 16971553Srgrimes exit(1); 16981553Srgrimes } 169915032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 170031492Swollman syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 17011553Srgrimes exit(1); 17021553Srgrimes } 170331492Swollman if (pp->baud_rate > 0) 170431492Swollman cfsetspeed(&ttybuf, pp->baud_rate); 170531492Swollman if (pp->mode_set) { 170631492Swollman char *s = strdup(pp->mode_set), *tmp; 170715032Ssef 170831492Swollman while ((tmp = strsep(&s, ",")) != NULL) { 170939084Swollman (void) msearch(tmp, &ttybuf); 17101553Srgrimes } 17111553Srgrimes } 171231492Swollman if (pp->mode_set != 0 || pp->baud_rate > 0) { 171315032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 171431492Swollman syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 17151553Srgrimes } 17161553Srgrimes } 17171553Srgrimes} 17181553Srgrimes 171927757Simp#ifdef __STDC__ 17201553Srgrimes#include <stdarg.h> 17211553Srgrimes#else 17221553Srgrimes#include <varargs.h> 17231553Srgrimes#endif 17241553Srgrimes 172515648Sjoergstatic void 172627757Simp#ifdef __STDC__ 172731492Swollmanpstatus(const struct printer *pp, const char *msg, ...) 17281553Srgrimes#else 172931492Swollmanpstatus(pp, msg, va_alist) 173031492Swollman const struct printer *pp; 17311553Srgrimes char *msg; 17321553Srgrimes va_dcl 17331553Srgrimes#endif 17341553Srgrimes{ 173531492Swollman int fd; 173631492Swollman char *buf; 17371553Srgrimes va_list ap; 173827757Simp#ifdef __STDC__ 17391553Srgrimes va_start(ap, msg); 17401553Srgrimes#else 17411553Srgrimes va_start(ap); 17421553Srgrimes#endif 17431553Srgrimes 17441553Srgrimes umask(0); 174531492Swollman fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 174631492Swollman if (fd < 0) { 174731492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 17481553Srgrimes exit(1); 17491553Srgrimes } 17501553Srgrimes ftruncate(fd, 0); 175131492Swollman vasprintf(&buf, msg, ap); 17521553Srgrimes va_end(ap); 175331492Swollman writel(fd, buf, "\n", (char *)0); 175431492Swollman close(fd); 175531492Swollman free(buf); 17561553Srgrimes} 175730407Sjoerg 175830407Sjoergvoid 175930407Sjoergalarmhandler(signo) 176030407Sjoerg{ 176130407Sjoerg /* ignored */ 176230407Sjoerg} 1763