printjob.c revision 78146
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 78146 2001-06-12 16:38:20Z 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 12478146Sgadstatic void abortpr(int _signo); 12578146Sgadstatic void alarmhandler(int _signo); 12678146Sgadstatic void banner(struct printer *_pp, char *_name1, char *_name2); 12778146Sgadstatic int dofork(const struct printer *_pp, int _action); 12878146Sgadstatic int dropit(int _c); 12978146Sgadstatic void init(struct printer *_pp); 13078146Sgadstatic void openpr(const struct printer *_pp); 13178146Sgadstatic void opennet(const struct printer *_pp); 13278146Sgadstatic void opentty(const struct printer *_pp); 13378146Sgadstatic void openrem(const struct printer *pp); 13478146Sgadstatic int print(struct printer *_pp, int _format, char *_file); 13578146Sgadstatic int printit(struct printer *_pp, char *_file); 13678146Sgadstatic void pstatus(const struct printer *_pp, const char *_msg, ...); 13778146Sgadstatic char response(const struct printer *_pp); 13878146Sgadstatic void scan_out(struct printer *_pp, int _scfd, char *_scsp, 13978146Sgad int _dlm); 14078146Sgadstatic char *scnline(int _key, char *_p, int _c); 14178146Sgadstatic int sendfile(struct printer *_pp, int _type, char *_file, 14278146Sgad char _format); 14378146Sgadstatic int sendit(struct printer *_pp, char *_file); 14478146Sgadstatic void sendmail(struct printer *_pp, char *_user, int _bombed); 14578146Sgadstatic void setty(const struct printer *_pp); 1461553Srgrimes 1471553Srgrimesvoid 14878146Sgadprintjob(struct printer *pp) 1491553Srgrimes{ 1501553Srgrimes struct stat stb; 15168401Sgad register struct jobqueue *q, **qp; 15268401Sgad struct jobqueue **queue; 1531553Srgrimes register int i, nitems; 15468733Sgad off_t pidoff; 15568733Sgad int errcnt, jobcount, tempfd; 1561553Srgrimes 15768733Sgad jobcount = 0; 15831492Swollman init(pp); /* set up capabilities */ 15931492Swollman (void) write(1, "", 1); /* ack that daemon is started */ 1601553Srgrimes (void) close(2); /* set up log file */ 16131492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 16231492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1631553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1641553Srgrimes } 1651553Srgrimes setgid(getegid()); 1661553Srgrimes pid = getpid(); /* for use with lprm */ 1671553Srgrimes setpgrp(0, pid); 1681553Srgrimes signal(SIGHUP, abortpr); 1691553Srgrimes signal(SIGINT, abortpr); 1701553Srgrimes signal(SIGQUIT, abortpr); 1711553Srgrimes signal(SIGTERM, abortpr); 1721553Srgrimes 1731553Srgrimes /* 1741553Srgrimes * uses short form file names 1751553Srgrimes */ 17631492Swollman if (chdir(pp->spool_dir) < 0) { 17731492Swollman syslog(LOG_ERR, "%s: %m", pp->spool_dir); 1781553Srgrimes exit(1); 1791553Srgrimes } 18031492Swollman if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 1811553Srgrimes exit(0); /* printing disabled */ 18231492Swollman lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 18331492Swollman LOCK_FILE_MODE); 1841553Srgrimes if (lfd < 0) { 18531492Swollman if (errno == EWOULDBLOCK) /* active daemon present */ 18631492Swollman exit(0); 18731492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 1881553Srgrimes exit(1); 1891553Srgrimes } 19031492Swollman /* turn off non-blocking mode (was turned on for lock effects only) */ 19131492Swollman if (fcntl(lfd, F_SETFL, 0) < 0) { 19231492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 1931553Srgrimes exit(1); 1941553Srgrimes } 1951553Srgrimes ftruncate(lfd, 0); 1961553Srgrimes /* 1971553Srgrimes * write process id for others to know 1981553Srgrimes */ 1991553Srgrimes sprintf(line, "%u\n", pid); 2001553Srgrimes pidoff = i = strlen(line); 2011553Srgrimes if (write(lfd, line, i) != i) { 20231492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 2031553Srgrimes exit(1); 2041553Srgrimes } 2051553Srgrimes /* 2061553Srgrimes * search the spool directory for work and sort by queue order. 2071553Srgrimes */ 20831492Swollman if ((nitems = getq(pp, &queue)) < 0) { 20931492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 21031492Swollman pp->spool_dir); 2111553Srgrimes exit(1); 2121553Srgrimes } 2131553Srgrimes if (nitems == 0) /* no work to do */ 2141553Srgrimes exit(0); 21531492Swollman if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 21631492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 21731492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 21831492Swollman pp->lock_file); 2191553Srgrimes } 22068664Sgad 22168664Sgad /* create a file which will be used to hold stderr from filters */ 22268664Sgad if ((tempfd = mkstemp(tempstderr)) == -1) { 22368664Sgad syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 22468664Sgad tempstderr); 22568732Sgad exit(1); 22668664Sgad } 22768664Sgad if ((i = fchmod(tempfd, 0664)) == -1) { 22868664Sgad syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 22968664Sgad tempstderr); 23068732Sgad exit(1); 23168664Sgad } 23268664Sgad /* lpd doesn't need it to be open, it just needs it to exist */ 23368664Sgad close(tempfd); 23468664Sgad 23531492Swollman openpr(pp); /* open printer or remote */ 2361553Srgrimesagain: 2371553Srgrimes /* 2381553Srgrimes * we found something to do now do it -- 2391553Srgrimes * write the name of the current control file into the lock file 2401553Srgrimes * so the spool queue program can tell what we're working on 2411553Srgrimes */ 2421553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2431553Srgrimes q = *qp++; 24468401Sgad if (stat(q->job_cfname, &stb) < 0) 2451553Srgrimes continue; 24615648Sjoerg errcnt = 0; 2471553Srgrimes restart: 24815648Sjoerg (void) lseek(lfd, pidoff, 0); 24968401Sgad (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 2501553Srgrimes i = strlen(line); 2511553Srgrimes if (write(lfd, line, i) != i) 25231492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 25331492Swollman pp->lock_file); 25431492Swollman if (!pp->remote) 25568401Sgad i = printit(pp, q->job_cfname); 2561553Srgrimes else 25768401Sgad i = sendit(pp, q->job_cfname); 2581553Srgrimes /* 2591553Srgrimes * Check to see if we are supposed to stop printing or 2601553Srgrimes * if we are to rebuild the queue. 2611553Srgrimes */ 2621553Srgrimes if (fstat(lfd, &stb) == 0) { 2631553Srgrimes /* stop printing before starting next job? */ 26431492Swollman if (stb.st_mode & LFM_PRINT_DIS) 2651553Srgrimes goto done; 2661553Srgrimes /* rebuild queue (after lpc topq) */ 26731492Swollman if (stb.st_mode & LFM_RESET_QUE) { 26831492Swollman for (free(q); nitems--; free(q)) 2691553Srgrimes q = *qp++; 27031492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 27131492Swollman < 0) 2721553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 27331492Swollman pp->printer, pp->lock_file); 2741553Srgrimes break; 2751553Srgrimes } 2761553Srgrimes } 27768733Sgad if (i == OK) /* all files of this job printed */ 27868733Sgad jobcount++; 27915648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 28015648Sjoerg /* try reprinting the job */ 28131492Swollman syslog(LOG_INFO, "restarting %s", pp->printer); 2821553Srgrimes if (ofilter > 0) { 2831553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2841553Srgrimes (void) close(ofd); 28515648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2861553Srgrimes ; 2871553Srgrimes ofilter = 0; 2881553Srgrimes } 2891553Srgrimes (void) close(pfd); /* close printer */ 2901553Srgrimes if (ftruncate(lfd, pidoff) < 0) 29131492Swollman syslog(LOG_WARNING, "%s: %s: %m", 29231492Swollman pp->printer, pp->lock_file); 29331492Swollman openpr(pp); /* try to reopen printer */ 2941553Srgrimes goto restart; 29515648Sjoerg } else { 29631492Swollman syslog(LOG_WARNING, "%s: job could not be %s (%s)", 29731492Swollman pp->printer, 29831492Swollman pp->remote ? "sent to remote host" : "printed", 29968401Sgad q->job_cfname); 30015648Sjoerg if (i == REPRINT) { 30127748Simp /* ensure we don't attempt this job again */ 30268401Sgad (void) unlink(q->job_cfname); 30368401Sgad q->job_cfname[0] = 'd'; 30468401Sgad (void) unlink(q->job_cfname); 30515648Sjoerg if (logname[0]) 30631492Swollman sendmail(pp, logname, FATALERR); 30715648Sjoerg } 3081553Srgrimes } 3091553Srgrimes } 31031492Swollman free(queue); 3111553Srgrimes /* 3121553Srgrimes * search the spool directory for more work. 3131553Srgrimes */ 31431492Swollman if ((nitems = getq(pp, &queue)) < 0) { 31531492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 31631492Swollman pp->spool_dir); 3171553Srgrimes exit(1); 3181553Srgrimes } 3191553Srgrimes if (nitems == 0) { /* no more work to do */ 3201553Srgrimes done: 32168733Sgad if (jobcount > 0) { /* jobs actually printed */ 32231492Swollman if (!pp->no_formfeed && !pp->tof) 32331492Swollman (void) write(ofd, pp->form_feed, 32431492Swollman strlen(pp->form_feed)); 32531492Swollman if (pp->trailer != NULL) /* output trailer */ 32631492Swollman (void) write(ofd, pp->trailer, 32731492Swollman strlen(pp->trailer)); 3281553Srgrimes } 32919202Simp (void) close(ofd); 33019202Simp (void) wait(NULL); 33168664Sgad (void) unlink(tempstderr); 3321553Srgrimes exit(0); 3331553Srgrimes } 3341553Srgrimes goto again; 3351553Srgrimes} 3361553Srgrimes 3371553Srgrimeschar fonts[4][50]; /* fonts for troff */ 3381553Srgrimes 3391553Srgrimeschar ifonts[4][40] = { 3401553Srgrimes _PATH_VFONTR, 3411553Srgrimes _PATH_VFONTI, 3421553Srgrimes _PATH_VFONTB, 3431553Srgrimes _PATH_VFONTS, 3441553Srgrimes}; 3451553Srgrimes 3461553Srgrimes/* 3471553Srgrimes * The remaining part is the reading of the control file (cf) 3481553Srgrimes * and performing the various actions. 3491553Srgrimes */ 3501553Srgrimesstatic int 35178146Sgadprintit(struct printer *pp, char *file) 3521553Srgrimes{ 3531553Srgrimes register int i; 35468734Sgad char *cp; 35568734Sgad int bombed, didignorehdr; 3561553Srgrimes 35768734Sgad bombed = OK; 35868734Sgad didignorehdr = 0; 3591553Srgrimes /* 3601553Srgrimes * open control file; ignore if no longer there. 3611553Srgrimes */ 3621553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 36331492Swollman syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 3641553Srgrimes return(OK); 3651553Srgrimes } 3661553Srgrimes /* 3671553Srgrimes * Reset troff fonts. 3681553Srgrimes */ 3691553Srgrimes for (i = 0; i < 4; i++) 3701553Srgrimes strcpy(fonts[i], ifonts[i]); 37131492Swollman sprintf(&width[2], "%ld", pp->page_width); 3721553Srgrimes strcpy(indent+2, "0"); 3731553Srgrimes 37468253Sgad /* initialize job-specific count of datafiles processed */ 37568253Sgad job_dfcnt = 0; 37668253Sgad 3771553Srgrimes /* 3781553Srgrimes * read the control file for work to do 3791553Srgrimes * 3801553Srgrimes * file format -- first character in the line is a command 3811553Srgrimes * rest of the line is the argument. 3821553Srgrimes * valid commands are: 3831553Srgrimes * 3841553Srgrimes * S -- "stat info" for symbolic link protection 3851553Srgrimes * J -- "job name" on banner page 3861553Srgrimes * C -- "class name" on banner page 3871553Srgrimes * L -- "literal" user's name to print on banner 3881553Srgrimes * T -- "title" for pr 3891553Srgrimes * H -- "host name" of machine where lpr was done 3901553Srgrimes * P -- "person" user's login name 3911553Srgrimes * I -- "indent" amount to indent output 39215648Sjoerg * R -- laser dpi "resolution" 3931553Srgrimes * f -- "file name" name of text file to print 3941553Srgrimes * l -- "file name" text file with control chars 3951553Srgrimes * p -- "file name" text file to print with pr(1) 3961553Srgrimes * t -- "file name" troff(1) file to print 3971553Srgrimes * n -- "file name" ditroff(1) file to print 3981553Srgrimes * d -- "file name" dvi file to print 3991553Srgrimes * g -- "file name" plot(1G) file to print 4001553Srgrimes * v -- "file name" plain raster file to print 4011553Srgrimes * c -- "file name" cifplot file to print 4021553Srgrimes * 1 -- "R font file" for troff 4031553Srgrimes * 2 -- "I font file" for troff 4041553Srgrimes * 3 -- "B font file" for troff 4051553Srgrimes * 4 -- "S font file" for troff 4061553Srgrimes * N -- "name" of file (used by lpq) 4071553Srgrimes * U -- "unlink" name of file to remove 4081553Srgrimes * (after we print it. (Pass 2 only)). 4091553Srgrimes * M -- "mail" to user when done printing 41053956Sache * Z -- "locale" for pr 4111553Srgrimes * 4121553Srgrimes * getline reads a line and expands tabs to blanks 4131553Srgrimes */ 4141553Srgrimes 4151553Srgrimes /* pass 1 */ 4161553Srgrimes 4171553Srgrimes while (getline(cfp)) 4181553Srgrimes switch (line[0]) { 4191553Srgrimes case 'H': 42027748Simp strncpy(fromhost, line+1, sizeof(fromhost) - 1); 42127748Simp fromhost[sizeof(fromhost) - 1] = '\0'; 42227748Simp if (class[0] == '\0') { 42327748Simp strncpy(class, line+1, sizeof(class) - 1); 42427748Simp class[sizeof(class) - 1] = '\0'; 42527748Simp } 4261553Srgrimes continue; 4271553Srgrimes 4281553Srgrimes case 'P': 42927748Simp strncpy(logname, line+1, sizeof(logname) - 1); 43027748Simp logname[sizeof(logname) - 1] = '\0'; 43131492Swollman if (pp->restricted) { /* restricted */ 4321553Srgrimes if (getpwnam(logname) == NULL) { 4331553Srgrimes bombed = NOACCT; 43431492Swollman sendmail(pp, line+1, bombed); 4351553Srgrimes goto pass2; 4361553Srgrimes } 4371553Srgrimes } 4381553Srgrimes continue; 4391553Srgrimes 4401553Srgrimes case 'S': 4411553Srgrimes cp = line+1; 4421553Srgrimes i = 0; 4431553Srgrimes while (*cp >= '0' && *cp <= '9') 4441553Srgrimes i = i * 10 + (*cp++ - '0'); 4451553Srgrimes fdev = i; 4461553Srgrimes cp++; 4471553Srgrimes i = 0; 4481553Srgrimes while (*cp >= '0' && *cp <= '9') 4491553Srgrimes i = i * 10 + (*cp++ - '0'); 4501553Srgrimes fino = i; 4511553Srgrimes continue; 4521553Srgrimes 4531553Srgrimes case 'J': 45427748Simp if (line[1] != '\0') { 45527748Simp strncpy(jobname, line+1, sizeof(jobname) - 1); 45627748Simp jobname[sizeof(jobname) - 1] = '\0'; 45727748Simp } else 4581553Srgrimes strcpy(jobname, " "); 4591553Srgrimes continue; 4601553Srgrimes 4611553Srgrimes case 'C': 4621553Srgrimes if (line[1] != '\0') 46327748Simp strncpy(class, line+1, sizeof(class) - 1); 4641553Srgrimes else if (class[0] == '\0') 4651553Srgrimes gethostname(class, sizeof(class)); 46627748Simp class[sizeof(class) - 1] = '\0'; 4671553Srgrimes continue; 4681553Srgrimes 4691553Srgrimes case 'T': /* header title for pr */ 47027748Simp strncpy(title, line+1, sizeof(title) - 1); 47127748Simp title[sizeof(title) - 1] = '\0'; 4721553Srgrimes continue; 4731553Srgrimes 4741553Srgrimes case 'L': /* identification line */ 47531492Swollman if (!pp->no_header && !pp->header_last) 47631492Swollman banner(pp, line+1, jobname); 4771553Srgrimes continue; 4781553Srgrimes 4791553Srgrimes case '1': /* troff fonts */ 4801553Srgrimes case '2': 4811553Srgrimes case '3': 4821553Srgrimes case '4': 48327748Simp if (line[1] != '\0') { 48427748Simp strncpy(fonts[line[0]-'1'], line+1, 48527748Simp 50-1); 48627748Simp fonts[line[0]-'1'][50-1] = '\0'; 48727748Simp } 4881553Srgrimes continue; 4891553Srgrimes 4901553Srgrimes case 'W': /* page width */ 49127748Simp strncpy(width+2, line+1, sizeof(width) - 3); 49227748Simp width[2+sizeof(width) - 3] = '\0'; 4931553Srgrimes continue; 4941553Srgrimes 4951553Srgrimes case 'I': /* indent amount */ 49627748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 49727748Simp indent[2+sizeof(indent) - 3] = '\0'; 4981553Srgrimes continue; 4991553Srgrimes 50053956Sache case 'Z': /* locale for pr */ 50153956Sache strncpy(locale, line+1, sizeof(locale) - 1); 50253956Sache locale[sizeof(locale) - 1] = '\0'; 50353956Sache continue; 50453956Sache 5051553Srgrimes default: /* some file to print */ 50668467Sgad /* only lowercase cmd-codes include a file-to-print */ 50768467Sgad if ((line[0] < 'a') || (line[0] > 'z')) { 50868467Sgad /* ignore any other lines */ 50968467Sgad if (lflag <= 1) 51068467Sgad continue; 51168467Sgad if (!didignorehdr) { 51268467Sgad syslog(LOG_INFO, "%s: in %s :", 51368467Sgad pp->printer, file); 51468467Sgad didignorehdr = 1; 51568467Sgad } 51668467Sgad syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 51768467Sgad pp->printer, line[0], &line[1]); 51868467Sgad continue; 51968467Sgad } 52068467Sgad i = print(pp, line[0], line+1); 52168467Sgad switch (i) { 5221553Srgrimes case ERROR: 5231553Srgrimes if (bombed == OK) 5241553Srgrimes bombed = FATALERR; 5251553Srgrimes break; 5261553Srgrimes case REPRINT: 5271553Srgrimes (void) fclose(cfp); 5281553Srgrimes return(REPRINT); 5291553Srgrimes case FILTERERR: 5301553Srgrimes case ACCESS: 5311553Srgrimes bombed = i; 53231492Swollman sendmail(pp, logname, bombed); 5331553Srgrimes } 5341553Srgrimes title[0] = '\0'; 5351553Srgrimes continue; 5361553Srgrimes 5371553Srgrimes case 'N': 5381553Srgrimes case 'U': 5391553Srgrimes case 'M': 54015648Sjoerg case 'R': 5411553Srgrimes continue; 5421553Srgrimes } 5431553Srgrimes 5441553Srgrimes /* pass 2 */ 5451553Srgrimes 5461553Srgrimespass2: 5471553Srgrimes fseek(cfp, 0L, 0); 5481553Srgrimes while (getline(cfp)) 5491553Srgrimes switch (line[0]) { 5501553Srgrimes case 'L': /* identification line */ 55131492Swollman if (!pp->no_header && pp->header_last) 55231492Swollman banner(pp, line+1, jobname); 5531553Srgrimes continue; 5541553Srgrimes 5551553Srgrimes case 'M': 5561553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 55731492Swollman sendmail(pp, line+1, bombed); 5581553Srgrimes continue; 5591553Srgrimes 5601553Srgrimes case 'U': 56127748Simp if (strchr(line+1, '/')) 56227748Simp continue; 5631553Srgrimes (void) unlink(line+1); 5641553Srgrimes } 5651553Srgrimes /* 5661553Srgrimes * clean-up in case another control file exists 5671553Srgrimes */ 5681553Srgrimes (void) fclose(cfp); 5691553Srgrimes (void) unlink(file); 5701553Srgrimes return(bombed == OK ? OK : ERROR); 5711553Srgrimes} 5721553Srgrimes 5731553Srgrimes/* 5741553Srgrimes * Print a file. 5751553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 5761553Srgrimes * Return -1 if a non-recoverable error occured, 5771553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 5781553Srgrimes * 1 if we should try to reprint this job and 5791553Srgrimes * 0 if all is well. 5801553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5811553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5821553Srgrimes */ 5831553Srgrimesstatic int 58478146Sgadprint(struct printer *pp, int format, char *file) 5851553Srgrimes{ 58653956Sache register int n, i; 5871553Srgrimes register char *prog; 58831492Swollman int fi, fo; 5891553Srgrimes FILE *fp; 5901553Srgrimes char *av[15], buf[BUFSIZ]; 59168734Sgad int pid, p[2], stopped; 5921553Srgrimes union wait status; 5931553Srgrimes struct stat stb; 5941553Srgrimes 59568467Sgad if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 59668467Sgad syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 59768467Sgad pp->printer, file, format); 5981553Srgrimes return(ERROR); 59968467Sgad } 6001553Srgrimes /* 6011553Srgrimes * Check to see if data file is a symbolic link. If so, it should 6021553Srgrimes * still point to the same file or someone is trying to print 6031553Srgrimes * something he shouldn't. 6041553Srgrimes */ 6051553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 6061553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 6071553Srgrimes return(ACCESS); 60868253Sgad 60968253Sgad job_dfcnt++; /* increment datafile counter for this job */ 61068734Sgad stopped = 0; /* output filter is not stopped */ 61168253Sgad 61268253Sgad /* everything seems OK, start it up */ 61331492Swollman if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 61431492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 61531492Swollman pp->tof = 1; 6161553Srgrimes } 61731492Swollman if (pp->filters[LPF_INPUT] == NULL 61831492Swollman && (format == 'f' || format == 'l')) { 61931492Swollman pp->tof = 0; 6201553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 6211553Srgrimes if (write(ofd, buf, n) != n) { 6221553Srgrimes (void) close(fi); 6231553Srgrimes return(REPRINT); 6241553Srgrimes } 6251553Srgrimes (void) close(fi); 6261553Srgrimes return(OK); 6271553Srgrimes } 6281553Srgrimes switch (format) { 6291553Srgrimes case 'p': /* print file using 'pr' */ 63031492Swollman if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 6311553Srgrimes prog = _PATH_PR; 63253956Sache i = 0; 63353956Sache av[i++] = "pr"; 63453956Sache av[i++] = width; 63553956Sache av[i++] = length; 63653956Sache av[i++] = "-h"; 63753956Sache av[i++] = *title ? title : " "; 63853956Sache av[i++] = "-L"; 63953956Sache av[i++] = *locale ? locale : "C"; 64053956Sache av[i++] = "-F"; 64153956Sache av[i] = 0; 6421553Srgrimes fo = ofd; 6431553Srgrimes goto start; 6441553Srgrimes } 6451553Srgrimes pipe(p); 64631492Swollman if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 6471553Srgrimes dup2(fi, 0); /* file is stdin */ 6481553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 6498094Sjkh closelog(); 65031492Swollman closeallfds(3); 6511553Srgrimes execl(_PATH_PR, "pr", width, length, 65253956Sache "-h", *title ? title : " ", 65353956Sache "-L", *locale ? locale : "C", 65453956Sache "-F", 0); 6551553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 6561553Srgrimes exit(2); 6571553Srgrimes } 6581553Srgrimes (void) close(p[1]); /* close output side */ 6591553Srgrimes (void) close(fi); 6601553Srgrimes if (prchild < 0) { 6611553Srgrimes prchild = 0; 6621553Srgrimes (void) close(p[0]); 6631553Srgrimes return(ERROR); 6641553Srgrimes } 6651553Srgrimes fi = p[0]; /* use pipe for input */ 6661553Srgrimes case 'f': /* print plain text file */ 66731492Swollman prog = pp->filters[LPF_INPUT]; 6681553Srgrimes av[1] = width; 6691553Srgrimes av[2] = length; 6701553Srgrimes av[3] = indent; 6711553Srgrimes n = 4; 6721553Srgrimes break; 6731553Srgrimes case 'l': /* like 'f' but pass control characters */ 67431492Swollman prog = pp->filters[LPF_INPUT]; 6751553Srgrimes av[1] = "-c"; 6761553Srgrimes av[2] = width; 6771553Srgrimes av[3] = length; 6781553Srgrimes av[4] = indent; 6791553Srgrimes n = 5; 6801553Srgrimes break; 6811553Srgrimes case 'r': /* print a fortran text file */ 68231492Swollman prog = pp->filters[LPF_FORTRAN]; 6831553Srgrimes av[1] = width; 6841553Srgrimes av[2] = length; 6851553Srgrimes n = 3; 6861553Srgrimes break; 6871553Srgrimes case 't': /* print troff output */ 6881553Srgrimes case 'n': /* print ditroff output */ 6891553Srgrimes case 'd': /* print tex output */ 6901553Srgrimes (void) unlink(".railmag"); 6911553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 69231492Swollman syslog(LOG_ERR, "%s: cannot create .railmag", 69331492Swollman pp->printer); 6941553Srgrimes (void) unlink(".railmag"); 6951553Srgrimes } else { 6961553Srgrimes for (n = 0; n < 4; n++) { 6971553Srgrimes if (fonts[n][0] != '/') 6981553Srgrimes (void) write(fo, _PATH_VFONT, 6991553Srgrimes sizeof(_PATH_VFONT) - 1); 7001553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 7011553Srgrimes (void) write(fo, "\n", 1); 7021553Srgrimes } 7031553Srgrimes (void) close(fo); 7041553Srgrimes } 70531492Swollman prog = (format == 't') ? pp->filters[LPF_TROFF] 70631492Swollman : ((format == 'n') ? pp->filters[LPF_DITROFF] 70731492Swollman : pp->filters[LPF_DVI]); 7081553Srgrimes av[1] = pxwidth; 7091553Srgrimes av[2] = pxlength; 7101553Srgrimes n = 3; 7111553Srgrimes break; 7121553Srgrimes case 'c': /* print cifplot output */ 71331492Swollman prog = pp->filters[LPF_CIFPLOT]; 7141553Srgrimes av[1] = pxwidth; 7151553Srgrimes av[2] = pxlength; 7161553Srgrimes n = 3; 7171553Srgrimes break; 7181553Srgrimes case 'g': /* print plot(1G) output */ 71931492Swollman prog = pp->filters[LPF_GRAPH]; 7201553Srgrimes av[1] = pxwidth; 7211553Srgrimes av[2] = pxlength; 7221553Srgrimes n = 3; 7231553Srgrimes break; 7241553Srgrimes case 'v': /* print raster output */ 72531492Swollman prog = pp->filters[LPF_RASTER]; 7261553Srgrimes av[1] = pxwidth; 7271553Srgrimes av[2] = pxlength; 7281553Srgrimes n = 3; 7291553Srgrimes break; 7301553Srgrimes default: 7311553Srgrimes (void) close(fi); 7321553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 73331492Swollman pp->printer, format); 7341553Srgrimes return(ERROR); 7351553Srgrimes } 73615648Sjoerg if (prog == NULL) { 73715648Sjoerg (void) close(fi); 73815648Sjoerg syslog(LOG_ERR, 73915648Sjoerg "%s: no filter found in printcap for format character '%c'", 74031492Swollman pp->printer, format); 74115648Sjoerg return(ERROR); 74215648Sjoerg } 74327635Simp if ((av[0] = strrchr(prog, '/')) != NULL) 7441553Srgrimes av[0]++; 7451553Srgrimes else 7461553Srgrimes av[0] = prog; 7471553Srgrimes av[n++] = "-n"; 7481553Srgrimes av[n++] = logname; 7491553Srgrimes av[n++] = "-h"; 7501553Srgrimes av[n++] = fromhost; 75131492Swollman av[n++] = pp->acct_file; 7521553Srgrimes av[n] = 0; 7531553Srgrimes fo = pfd; 7541553Srgrimes if (ofilter > 0) { /* stop output filter */ 7551553Srgrimes write(ofd, "\031\1", 2); 7561553Srgrimes while ((pid = 7571553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 7581553Srgrimes ; 7591553Srgrimes if (status.w_stopval != WSTOPPED) { 7601553Srgrimes (void) close(fi); 76115648Sjoerg syslog(LOG_WARNING, 76231492Swollman "%s: output filter died " 76331492Swollman "(retcode=%d termsig=%d)", 76431492Swollman pp->printer, status.w_retcode, 76531492Swollman status.w_termsig); 7661553Srgrimes return(REPRINT); 7671553Srgrimes } 7681553Srgrimes stopped++; 7691553Srgrimes } 7701553Srgrimesstart: 77131492Swollman if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 7721553Srgrimes dup2(fi, 0); 7731553Srgrimes dup2(fo, 1); 77468664Sgad /* setup stderr for the filter (child process) 77568664Sgad * so it goes to our temporary errors file */ 77668664Sgad n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 7771553Srgrimes if (n >= 0) 7781553Srgrimes dup2(n, 2); 7798094Sjkh closelog(); 78031492Swollman closeallfds(3); 7811553Srgrimes execv(prog, av); 7821553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 7831553Srgrimes exit(2); 7841553Srgrimes } 7851553Srgrimes (void) close(fi); 7861553Srgrimes if (child < 0) 7871553Srgrimes status.w_retcode = 100; 7881553Srgrimes else 7891553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 7901553Srgrimes ; 7911553Srgrimes child = 0; 7921553Srgrimes prchild = 0; 7931553Srgrimes if (stopped) { /* restart output filter */ 7941553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 7951553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 7961553Srgrimes exit(1); 7971553Srgrimes } 7981553Srgrimes } 79931492Swollman pp->tof = 0; 8001553Srgrimes 80168664Sgad /* Copy the filter's output to "lf" logfile */ 80268664Sgad if ((fp = fopen(tempstderr, "r"))) { 8031553Srgrimes while (fgets(buf, sizeof(buf), fp)) 8041553Srgrimes fputs(buf, stderr); 8051553Srgrimes fclose(fp); 8061553Srgrimes } 8071553Srgrimes 8081553Srgrimes if (!WIFEXITED(status)) { 80915648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 81031492Swollman pp->printer, format, status.w_termsig); 8111553Srgrimes return(ERROR); 8121553Srgrimes } 8131553Srgrimes switch (status.w_retcode) { 8141553Srgrimes case 0: 81531492Swollman pp->tof = 1; 8161553Srgrimes return(OK); 8171553Srgrimes case 1: 8181553Srgrimes return(REPRINT); 81915648Sjoerg case 2: 82015648Sjoerg return(ERROR); 8211553Srgrimes default: 82215648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 82331492Swollman pp->printer, format, status.w_retcode); 82415648Sjoerg return(FILTERERR); 8251553Srgrimes } 8261553Srgrimes} 8271553Srgrimes 8281553Srgrimes/* 8291553Srgrimes * Send the daemon control file (cf) and any data files. 8301553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 8311553Srgrimes * 0 if all is well. 8321553Srgrimes */ 8331553Srgrimesstatic int 83478146Sgadsendit(struct printer *pp, char *file) 8351553Srgrimes{ 8361553Srgrimes register int i, err = OK; 8371553Srgrimes char *cp, last[BUFSIZ]; 8381553Srgrimes 8391553Srgrimes /* 8401553Srgrimes * open control file 8411553Srgrimes */ 8421553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 8431553Srgrimes return(OK); 84468253Sgad 84568253Sgad /* initialize job-specific count of datafiles processed */ 84668253Sgad job_dfcnt = 0; 84768253Sgad 8481553Srgrimes /* 8491553Srgrimes * read the control file for work to do 8501553Srgrimes * 8511553Srgrimes * file format -- first character in the line is a command 8521553Srgrimes * rest of the line is the argument. 8531553Srgrimes * commands of interest are: 8541553Srgrimes * 8551553Srgrimes * a-z -- "file name" name of file to print 8561553Srgrimes * U -- "unlink" name of file to remove 8571553Srgrimes * (after we print it. (Pass 2 only)). 8581553Srgrimes */ 8591553Srgrimes 8601553Srgrimes /* 8611553Srgrimes * pass 1 8621553Srgrimes */ 8631553Srgrimes while (getline(cfp)) { 8641553Srgrimes again: 8651553Srgrimes if (line[0] == 'S') { 8661553Srgrimes cp = line+1; 8671553Srgrimes i = 0; 8681553Srgrimes while (*cp >= '0' && *cp <= '9') 8691553Srgrimes i = i * 10 + (*cp++ - '0'); 8701553Srgrimes fdev = i; 8711553Srgrimes cp++; 8721553Srgrimes i = 0; 8731553Srgrimes while (*cp >= '0' && *cp <= '9') 8741553Srgrimes i = i * 10 + (*cp++ - '0'); 8751553Srgrimes fino = i; 87624831Sbrian } else if (line[0] == 'H') { 87768343Sgad strncpy(fromhost, line+1, sizeof(fromhost) - 1); 87868343Sgad fromhost[sizeof(fromhost) - 1] = '\0'; 87968343Sgad if (class[0] == '\0') { 88027748Simp strncpy(class, line+1, sizeof(class) - 1); 88168343Sgad class[sizeof(class) - 1] = '\0'; 88268343Sgad } 88324831Sbrian } else if (line[0] == 'P') { 88427748Simp strncpy(logname, line+1, sizeof(logname) - 1); 88568741Sgad logname[sizeof(logname) - 1] = '\0'; 88631492Swollman if (pp->restricted) { /* restricted */ 88724831Sbrian if (getpwnam(logname) == NULL) { 88831492Swollman sendmail(pp, line+1, NOACCT); 88924831Sbrian err = ERROR; 89024831Sbrian break; 89124831Sbrian } 89224831Sbrian } 89324831Sbrian } else if (line[0] == 'I') { 89427748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 89568741Sgad indent[2 + sizeof(indent) - 3] = '\0'; 89624831Sbrian } else if (line[0] >= 'a' && line[0] <= 'z') { 8971553Srgrimes strcpy(last, line); 89831492Swollman while ((i = getline(cfp)) != 0) 8991553Srgrimes if (strcmp(last, line)) 9001553Srgrimes break; 90131492Swollman switch (sendfile(pp, '\3', last+1, *last)) { 9021553Srgrimes case OK: 9031553Srgrimes if (i) 9041553Srgrimes goto again; 9051553Srgrimes break; 9061553Srgrimes case REPRINT: 9071553Srgrimes (void) fclose(cfp); 9081553Srgrimes return(REPRINT); 9091553Srgrimes case ACCESS: 91031492Swollman sendmail(pp, logname, ACCESS); 9111553Srgrimes case ERROR: 9121553Srgrimes err = ERROR; 9131553Srgrimes } 9141553Srgrimes break; 9151553Srgrimes } 9161553Srgrimes } 91731492Swollman if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 9181553Srgrimes (void) fclose(cfp); 9191553Srgrimes return(REPRINT); 9201553Srgrimes } 9211553Srgrimes /* 9221553Srgrimes * pass 2 9231553Srgrimes */ 9241553Srgrimes fseek(cfp, 0L, 0); 9251553Srgrimes while (getline(cfp)) 92627748Simp if (line[0] == 'U' && !strchr(line+1, '/')) 9271553Srgrimes (void) unlink(line+1); 9281553Srgrimes /* 9291553Srgrimes * clean-up in case another control file exists 9301553Srgrimes */ 9311553Srgrimes (void) fclose(cfp); 9321553Srgrimes (void) unlink(file); 9331553Srgrimes return(err); 9341553Srgrimes} 9351553Srgrimes 9361553Srgrimes/* 9371553Srgrimes * Send a data file to the remote machine and spool it. 9381553Srgrimes * Return positive if we should try resending. 9391553Srgrimes */ 9401553Srgrimesstatic int 94178146Sgadsendfile(struct printer *pp, int type, char *file, char format) 9421553Srgrimes{ 9431553Srgrimes register int f, i, amt; 9441553Srgrimes struct stat stb; 94568664Sgad FILE *fp; 9461553Srgrimes char buf[BUFSIZ]; 94774124Sgad int closedpr, resp, sizerr, statrc; 9481553Srgrimes 94974124Sgad statrc = lstat(file, &stb); 95074124Sgad if (statrc < 0) { 95174124Sgad syslog(LOG_ERR, "%s: error from lstat(%s): %m", 95274124Sgad pp->printer, file); 9531553Srgrimes return(ERROR); 95474124Sgad } 95574124Sgad f = open(file, O_RDONLY); 95674124Sgad if (f < 0) { 95774124Sgad syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 95874124Sgad pp->printer, file); 95974124Sgad return(ERROR); 96074124Sgad } 9611553Srgrimes /* 9621553Srgrimes * Check to see if data file is a symbolic link. If so, it should 9631553Srgrimes * still point to the same file or someone is trying to print something 9641553Srgrimes * he shouldn't. 9651553Srgrimes */ 9661553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 9671553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 9681553Srgrimes return(ACCESS); 96924831Sbrian 97068253Sgad job_dfcnt++; /* increment datafile counter for this job */ 97168253Sgad 97268253Sgad /* everything seems OK, start it up */ 97324831Sbrian sizerr = 0; 97424831Sbrian closedpr = 0; 97524831Sbrian if (type == '\3') { 97631492Swollman if (pp->filters[LPF_INPUT]) { 97724831Sbrian /* 97874124Sgad * We're sending something with an ifilter. We have to 97974124Sgad * run the ifilter and store the output as a temporary 98074124Sgad * spool file (tfile...), because the protocol requires 98174124Sgad * us to send the file size before we start sending any 98274124Sgad * of the data. 98324831Sbrian */ 98424831Sbrian char *av[15]; 98524831Sbrian int n; 98624831Sbrian int ifilter; 98731492Swollman union wait status; /* XXX */ 98824831Sbrian 98924831Sbrian strcpy(tfile,TFILENAME); 99024831Sbrian if ((tfd = mkstemp(tfile)) == -1) { 99124831Sbrian syslog(LOG_ERR, "mkstemp: %m"); 99224831Sbrian return(ERROR); 99324831Sbrian } 99431492Swollman if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 99531492Swollman av[0] = pp->filters[LPF_INPUT]; 99624831Sbrian else 99724831Sbrian av[0]++; 99824831Sbrian if (format == 'l') 99924831Sbrian av[n=1] = "-c"; 100024831Sbrian else 100124831Sbrian n = 0; 100224831Sbrian av[++n] = width; 100324831Sbrian av[++n] = length; 100424831Sbrian av[++n] = indent; 100524831Sbrian av[++n] = "-n"; 100624831Sbrian av[++n] = logname; 100724831Sbrian av[++n] = "-h"; 100824831Sbrian av[++n] = fromhost; 100931492Swollman av[++n] = pp->acct_file; 101024831Sbrian av[++n] = 0; 101131492Swollman if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 101224831Sbrian dup2(f, 0); 101324831Sbrian dup2(tfd, 1); 101468664Sgad /* setup stderr for the filter (child process) 101568664Sgad * so it goes to our temporary errors file */ 101668664Sgad n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 101724831Sbrian if (n >= 0) 101824831Sbrian dup2(n, 2); 101924831Sbrian closelog(); 102031492Swollman closeallfds(3); 102131492Swollman execv(pp->filters[LPF_INPUT], av); 102231492Swollman syslog(LOG_ERR, "cannot execv %s", 102331492Swollman pp->filters[LPF_INPUT]); 102424831Sbrian exit(2); 102524831Sbrian } 102624831Sbrian (void) close(f); 102724831Sbrian if (ifilter < 0) 102824831Sbrian status.w_retcode = 100; 102924831Sbrian else 103024831Sbrian while ((pid = wait((int *)&status)) > 0 && 103124831Sbrian pid != ifilter) 103224831Sbrian ; 103368664Sgad /* Copy the filter's output to "lf" logfile */ 103468664Sgad if ((fp = fopen(tempstderr, "r"))) { 103568664Sgad while (fgets(buf, sizeof(buf), fp)) 103668664Sgad fputs(buf, stderr); 103768664Sgad fclose(fp); 103868664Sgad } 103968664Sgad /* process the return-code from the filter */ 104024831Sbrian switch (status.w_retcode) { 104124831Sbrian case 0: 104224831Sbrian break; 104324831Sbrian case 1: 104424831Sbrian unlink(tfile); 104524831Sbrian return(REPRINT); 104624831Sbrian case 2: 104724831Sbrian unlink(tfile); 104824831Sbrian return(ERROR); 104924831Sbrian default: 105024831Sbrian syslog(LOG_WARNING, "%s: filter '%c' exited" 105124831Sbrian " (retcode=%d)", 105231492Swollman pp->printer, format, status.w_retcode); 105324831Sbrian unlink(tfile); 105424831Sbrian return(FILTERERR); 105524831Sbrian } 105674124Sgad statrc = fstat(tfd, &stb); /* to find size of tfile */ 105774124Sgad if (statrc < 0) { 105874124Sgad syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m", 105974124Sgad pp->printer, tfile); 106024831Sbrian return(ERROR); 106174124Sgad } 106224831Sbrian f = tfd; 106324831Sbrian lseek(f,0,SEEK_SET); 106424831Sbrian } else if (ofilter) { 106524831Sbrian /* 106624831Sbrian * We're sending something with an ofilter, we have to 106724831Sbrian * store the output as a temporary file (tfile)... the 106824831Sbrian * protocol requires us to send the file size 106924831Sbrian */ 107024831Sbrian int i; 107124831Sbrian for (i = 0; i < stb.st_size; i += BUFSIZ) { 107224831Sbrian amt = BUFSIZ; 107324831Sbrian if (i + amt > stb.st_size) 107424831Sbrian amt = stb.st_size - i; 107524831Sbrian if (sizerr == 0 && read(f, buf, amt) != amt) { 107624831Sbrian sizerr = 1; 107724831Sbrian break; 107824831Sbrian } 107924831Sbrian if (write(ofd, buf, amt) != amt) { 108024831Sbrian (void) close(f); 108124831Sbrian return(REPRINT); 108224831Sbrian } 108324831Sbrian } 108424831Sbrian close(ofd); 108524831Sbrian close(f); 108624831Sbrian while ((i = wait(NULL)) > 0 && i != ofilter) 108724831Sbrian ; 108824831Sbrian ofilter = 0; 108974124Sgad statrc = fstat(tfd, &stb); /* to find size of tfile */ 109074124Sgad if (statrc < 0) { 109174124Sgad syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m", 109274124Sgad pp->printer, tfile); 109331492Swollman openpr(pp); 109424831Sbrian return(ERROR); 109524831Sbrian } 109624831Sbrian f = tfd; 109724831Sbrian lseek(f,0,SEEK_SET); 109824831Sbrian closedpr = 1; 109924831Sbrian } 110024831Sbrian } 110124831Sbrian 11021553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 11031553Srgrimes amt = strlen(buf); 11041553Srgrimes for (i = 0; ; i++) { 11051553Srgrimes if (write(pfd, buf, amt) != amt || 110631492Swollman (resp = response(pp)) < 0 || resp == '\1') { 11071553Srgrimes (void) close(f); 110824831Sbrian if (tfd != -1 && type == '\3') { 110924831Sbrian tfd = -1; 111024831Sbrian unlink(tfile); 111124831Sbrian if (closedpr) 111231492Swollman openpr(pp); 111324831Sbrian } 11141553Srgrimes return(REPRINT); 11151553Srgrimes } else if (resp == '\0') 11161553Srgrimes break; 11171553Srgrimes if (i == 0) 111831492Swollman pstatus(pp, 111931492Swollman "no space on remote; waiting for queue to drain"); 11201553Srgrimes if (i == 10) 11211553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 112231492Swollman pp->printer, pp->remote_host); 11231553Srgrimes sleep(5 * 60); 11241553Srgrimes } 11251553Srgrimes if (i) 112631492Swollman pstatus(pp, "sending to %s", pp->remote_host); 112768253Sgad if (type == '\3') 112868253Sgad trstat_init(pp, file, job_dfcnt); 11291553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 11301553Srgrimes amt = BUFSIZ; 11311553Srgrimes if (i + amt > stb.st_size) 11321553Srgrimes amt = stb.st_size - i; 11331553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 11341553Srgrimes sizerr = 1; 11351553Srgrimes if (write(pfd, buf, amt) != amt) { 11361553Srgrimes (void) close(f); 113724831Sbrian if (tfd != -1 && type == '\3') { 113824831Sbrian tfd = -1; 113924831Sbrian unlink(tfile); 114024831Sbrian if (closedpr) 114131492Swollman openpr(pp); 114224831Sbrian } 11431553Srgrimes return(REPRINT); 11441553Srgrimes } 11451553Srgrimes } 11461553Srgrimes 11471553Srgrimes (void) close(f); 114824831Sbrian if (tfd != -1 && type == '\3') { 114924831Sbrian tfd = -1; 115024831Sbrian unlink(tfile); 115124831Sbrian } 11521553Srgrimes if (sizerr) { 115331492Swollman syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 11541553Srgrimes /* tell recvjob to ignore this file */ 11551553Srgrimes (void) write(pfd, "\1", 1); 115624831Sbrian if (closedpr) 115731492Swollman openpr(pp); 11581553Srgrimes return(ERROR); 11591553Srgrimes } 116031492Swollman if (write(pfd, "", 1) != 1 || response(pp)) { 116124831Sbrian if (closedpr) 116231492Swollman openpr(pp); 11631553Srgrimes return(REPRINT); 116424831Sbrian } 116524831Sbrian if (closedpr) 116631492Swollman openpr(pp); 116768253Sgad if (type == '\3') 116868253Sgad trstat_write(pp, TR_SENDING, stb.st_size, logname, 116968253Sgad pp->remote_host, fromhost); 11701553Srgrimes return(OK); 11711553Srgrimes} 11721553Srgrimes 11731553Srgrimes/* 11741553Srgrimes * Check to make sure there have been no errors and that both programs 11751553Srgrimes * are in sync with eachother. 11761553Srgrimes * Return non-zero if the connection was lost. 11771553Srgrimes */ 11781553Srgrimesstatic char 117978146Sgadresponse(const struct printer *pp) 11801553Srgrimes{ 11811553Srgrimes char resp; 11821553Srgrimes 11831553Srgrimes if (read(pfd, &resp, 1) != 1) { 118431492Swollman syslog(LOG_INFO, "%s: lost connection", pp->printer); 11851553Srgrimes return(-1); 11861553Srgrimes } 11871553Srgrimes return(resp); 11881553Srgrimes} 11891553Srgrimes 11901553Srgrimes/* 11911553Srgrimes * Banner printing stuff 11921553Srgrimes */ 11931553Srgrimesstatic void 119478146Sgadbanner(struct printer *pp, char *name1, char *name2) 11951553Srgrimes{ 11961553Srgrimes time_t tvec; 11971553Srgrimes 11981553Srgrimes time(&tvec); 119931492Swollman if (!pp->no_formfeed && !pp->tof) 120031492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 120131492Swollman if (pp->short_banner) { /* short banner only */ 12021553Srgrimes if (class[0]) { 12031553Srgrimes (void) write(ofd, class, strlen(class)); 12041553Srgrimes (void) write(ofd, ":", 1); 12051553Srgrimes } 12061553Srgrimes (void) write(ofd, name1, strlen(name1)); 12071553Srgrimes (void) write(ofd, " Job: ", 7); 12081553Srgrimes (void) write(ofd, name2, strlen(name2)); 12091553Srgrimes (void) write(ofd, " Date: ", 8); 12101553Srgrimes (void) write(ofd, ctime(&tvec), 24); 12111553Srgrimes (void) write(ofd, "\n", 1); 12121553Srgrimes } else { /* normal banner */ 12131553Srgrimes (void) write(ofd, "\n\n\n", 3); 121431492Swollman scan_out(pp, ofd, name1, '\0'); 12151553Srgrimes (void) write(ofd, "\n\n", 2); 121631492Swollman scan_out(pp, ofd, name2, '\0'); 12171553Srgrimes if (class[0]) { 12181553Srgrimes (void) write(ofd,"\n\n\n",3); 121931492Swollman scan_out(pp, ofd, class, '\0'); 12201553Srgrimes } 12211553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 12221553Srgrimes (void) write(ofd, name2, strlen(name2)); 12231553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 12241553Srgrimes (void) write(ofd, ctime(&tvec), 24); 12251553Srgrimes (void) write(ofd, "\n", 1); 12261553Srgrimes } 122731492Swollman if (!pp->no_formfeed) 122831492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 122931492Swollman pp->tof = 1; 12301553Srgrimes} 12311553Srgrimes 12321553Srgrimesstatic char * 123378146Sgadscnline(int key, char *p, int c) 12341553Srgrimes{ 123539084Swollman register int scnwidth; 12361553Srgrimes 12371553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 12381553Srgrimes key <<= 1; 12391553Srgrimes *p++ = key & 0200 ? c : BACKGND; 12401553Srgrimes } 12411553Srgrimes return (p); 12421553Srgrimes} 12431553Srgrimes 12441553Srgrimes#define TRC(q) (((q)-' ')&0177) 12451553Srgrimes 12461553Srgrimesstatic void 124778146Sgadscan_out(struct printer *pp, int scfd, char *scsp, int dlm) 12481553Srgrimes{ 12491553Srgrimes register char *strp; 125039084Swollman register int nchrs, j; 12511553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 12521553Srgrimes int d, scnhgt; 12531553Srgrimes 12541553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 12551553Srgrimes strp = &outbuf[0]; 12561553Srgrimes sp = scsp; 12571553Srgrimes for (nchrs = 0; ; ) { 12581553Srgrimes d = dropit(c = TRC(cc = *sp++)); 12591553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 12601553Srgrimes for (j = WIDTH; --j;) 12611553Srgrimes *strp++ = BACKGND; 12621553Srgrimes else 126331492Swollman strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 126431492Swollman if (*sp == dlm || *sp == '\0' || 126531492Swollman nchrs++ >= pp->page_width/(WIDTH+1)-1) 12661553Srgrimes break; 12671553Srgrimes *strp++ = BACKGND; 12681553Srgrimes *strp++ = BACKGND; 12691553Srgrimes } 12701553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 12711553Srgrimes ; 12721553Srgrimes strp++; 12738857Srgrimes *strp++ = '\n'; 12741553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 12751553Srgrimes } 12761553Srgrimes} 12771553Srgrimes 12781553Srgrimesstatic int 127978146Sgaddropit(int c) 12801553Srgrimes{ 12811553Srgrimes switch(c) { 12821553Srgrimes 12831553Srgrimes case TRC('_'): 12841553Srgrimes case TRC(';'): 12851553Srgrimes case TRC(','): 12861553Srgrimes case TRC('g'): 12871553Srgrimes case TRC('j'): 12881553Srgrimes case TRC('p'): 12891553Srgrimes case TRC('q'): 12901553Srgrimes case TRC('y'): 12911553Srgrimes return (DROP); 12921553Srgrimes 12931553Srgrimes default: 12941553Srgrimes return (0); 12951553Srgrimes } 12961553Srgrimes} 12971553Srgrimes 12981553Srgrimes/* 12991553Srgrimes * sendmail --- 13001553Srgrimes * tell people about job completion 13011553Srgrimes */ 13021553Srgrimesstatic void 130378146Sgadsendmail(struct printer *pp, char *user, int bombed) 13041553Srgrimes{ 13051553Srgrimes register int i; 13061553Srgrimes int p[2], s; 130778146Sgad register const char *cp; 13081553Srgrimes struct stat stb; 13091553Srgrimes FILE *fp; 13101553Srgrimes 13111553Srgrimes pipe(p); 131231492Swollman if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 13131553Srgrimes dup2(p[0], 0); 13148094Sjkh closelog(); 131531492Swollman closeallfds(3); 131627635Simp if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 13171553Srgrimes cp++; 131831492Swollman else 13191553Srgrimes cp = _PATH_SENDMAIL; 132027757Simp execl(_PATH_SENDMAIL, cp, "-t", 0); 132131492Swollman _exit(0); 13221553Srgrimes } else if (s > 0) { /* parent */ 13231553Srgrimes dup2(p[1], 1); 13241553Srgrimes printf("To: %s@%s\n", user, fromhost); 132531492Swollman printf("Subject: %s printer job \"%s\"\n", pp->printer, 132615648Sjoerg *jobname ? jobname : "<unknown>"); 132715648Sjoerg printf("Reply-To: root@%s\n\n", host); 13281553Srgrimes printf("Your printer job "); 13291553Srgrimes if (*jobname) 13301553Srgrimes printf("(%s) ", jobname); 133131492Swollman 133231492Swollman cp = "XXX compiler confusion"; /* XXX shut GCC up */ 13331553Srgrimes switch (bombed) { 13341553Srgrimes case OK: 13351553Srgrimes printf("\ncompleted successfully\n"); 133615648Sjoerg cp = "OK"; 13371553Srgrimes break; 13381553Srgrimes default: 13391553Srgrimes case FATALERR: 13401553Srgrimes printf("\ncould not be printed\n"); 134115648Sjoerg cp = "FATALERR"; 13421553Srgrimes break; 13431553Srgrimes case NOACCT: 13441553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 134515648Sjoerg cp = "NOACCT"; 13461553Srgrimes break; 13471553Srgrimes case FILTERERR: 134868664Sgad if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 134968664Sgad || (fp = fopen(tempstderr, "r")) == NULL) { 135015648Sjoerg printf("\nhad some errors and may not have printed\n"); 13511553Srgrimes break; 13521553Srgrimes } 135315648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 13541553Srgrimes while ((i = getc(fp)) != EOF) 13551553Srgrimes putchar(i); 13561553Srgrimes (void) fclose(fp); 135715648Sjoerg cp = "FILTERERR"; 13581553Srgrimes break; 13591553Srgrimes case ACCESS: 13601553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 136115648Sjoerg cp = "ACCESS"; 13621553Srgrimes } 13631553Srgrimes fflush(stdout); 13641553Srgrimes (void) close(1); 136531492Swollman } else { 136631492Swollman syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 136731492Swollman return; 13681553Srgrimes } 13691553Srgrimes (void) close(p[0]); 13701553Srgrimes (void) close(p[1]); 137115648Sjoerg wait(NULL); 137215648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 137331492Swollman user, *jobname ? jobname : "<unknown>", pp->printer, cp); 13741553Srgrimes} 13751553Srgrimes 13761553Srgrimes/* 13771553Srgrimes * dofork - fork with retries on failure 13781553Srgrimes */ 13791553Srgrimesstatic int 138078146Sgaddofork(const struct printer *pp, int action) 13811553Srgrimes{ 138278146Sgad register int i, forkpid; 138360871Smpp struct passwd *pwd; 13841553Srgrimes 13851553Srgrimes for (i = 0; i < 20; i++) { 138678146Sgad if ((forkpid = fork()) < 0) { 13871553Srgrimes sleep((unsigned)(i*i)); 13881553Srgrimes continue; 13891553Srgrimes } 13901553Srgrimes /* 13911553Srgrimes * Child should run as daemon instead of root 13921553Srgrimes */ 139378146Sgad if (forkpid == 0) { 139460871Smpp if ((pwd = getpwuid(pp->daemon_user)) == NULL) { 139568379Sgad syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", 139660871Smpp pp->daemon_user); 139760871Smpp break; 139860871Smpp } 139960871Smpp initgroups(pwd->pw_name, pwd->pw_gid); 140060871Smpp setgid(pwd->pw_gid); 140131492Swollman setuid(pp->daemon_user); 140260871Smpp } 140378146Sgad return(forkpid); 14041553Srgrimes } 14051553Srgrimes syslog(LOG_ERR, "can't fork"); 14061553Srgrimes 14071553Srgrimes switch (action) { 14081553Srgrimes case DORETURN: 14091553Srgrimes return (-1); 14101553Srgrimes default: 14111553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 14121553Srgrimes /*FALL THRU*/ 14131553Srgrimes case DOABORT: 14141553Srgrimes exit(1); 14151553Srgrimes } 14161553Srgrimes /*NOTREACHED*/ 14171553Srgrimes} 14181553Srgrimes 14191553Srgrimes/* 14201553Srgrimes * Kill child processes to abort current job. 14211553Srgrimes */ 14221553Srgrimesstatic void 142378146Sgadabortpr(int signo __unused) 14241553Srgrimes{ 142568664Sgad 142668664Sgad (void) unlink(tempstderr); 14271553Srgrimes kill(0, SIGINT); 14281553Srgrimes if (ofilter > 0) 14291553Srgrimes kill(ofilter, SIGCONT); 14301553Srgrimes while (wait(NULL) > 0) 14311553Srgrimes ; 143224831Sbrian if (ofilter > 0 && tfd != -1) 143324831Sbrian unlink(tfile); 14341553Srgrimes exit(0); 14351553Srgrimes} 14361553Srgrimes 14371553Srgrimesstatic void 143878146Sgadinit(struct printer *pp) 14391553Srgrimes{ 14401553Srgrimes char *s; 14411553Srgrimes 144231492Swollman sprintf(&width[2], "%ld", pp->page_width); 144331492Swollman sprintf(&length[2], "%ld", pp->page_length); 144431492Swollman sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 144531492Swollman sprintf(&pxlength[2], "%ld", pp->page_plength); 144631492Swollman if ((s = checkremote(pp)) != 0) { 144731492Swollman syslog(LOG_WARNING, "%s", s); 144831492Swollman free(s); 144931492Swollman } 145031492Swollman} 145131492Swollman 145231492Swollmanvoid 145378146Sgadstartprinting(const char *printer) 145431492Swollman{ 145531492Swollman struct printer myprinter, *pp = &myprinter; 145631492Swollman int status; 145731492Swollman 145831492Swollman init_printer(pp); 145931492Swollman status = getprintcap(printer, pp); 146031492Swollman switch(status) { 146131492Swollman case PCAPERR_OSERR: 146231492Swollman syslog(LOG_ERR, "can't open printer description file: %m"); 14631553Srgrimes exit(1); 146431492Swollman case PCAPERR_NOTFOUND: 14651553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 14661553Srgrimes exit(1); 146731492Swollman case PCAPERR_TCLOOP: 146831492Swollman fatal(pp, "potential reference loop detected in printcap file"); 146931492Swollman default: 147031492Swollman break; 147131492Swollman } 147231492Swollman printjob(pp); 14731553Srgrimes} 14741553Srgrimes 14751553Srgrimes/* 14761553Srgrimes * Acquire line printer or remote connection. 14771553Srgrimes */ 14781553Srgrimesstatic void 147978146Sgadopenpr(const struct printer *pp) 14801553Srgrimes{ 148131492Swollman int p[2]; 148215648Sjoerg char *cp; 14831553Srgrimes 148431492Swollman if (pp->remote) { 148531492Swollman openrem(pp); 148631492Swollman } else if (*pp->lp) { 148731492Swollman if ((cp = strchr(pp->lp, '@')) != NULL) 148831492Swollman opennet(pp); 148915648Sjoerg else 149031492Swollman opentty(pp); 14911553Srgrimes } else { 14921553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 149331492Swollman pp->printer); 14941553Srgrimes exit(1); 14951553Srgrimes } 149615648Sjoerg 14971553Srgrimes /* 14981553Srgrimes * Start up an output filter, if needed. 14991553Srgrimes */ 150031492Swollman if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 15011553Srgrimes pipe(p); 150231492Swollman if (pp->remote) { 150331492Swollman strcpy(tfile, TFILENAME); 150424831Sbrian tfd = mkstemp(tfile); 150524831Sbrian } 150631492Swollman if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 15071553Srgrimes dup2(p[0], 0); /* pipe is std in */ 150824831Sbrian /* tfile/printer is stdout */ 150931492Swollman dup2(pp->remote ? tfd : pfd, 1); 15108094Sjkh closelog(); 151131492Swollman closeallfds(3); 151231492Swollman if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 151331492Swollman cp = pp->filters[LPF_OUTPUT]; 15141553Srgrimes else 15151553Srgrimes cp++; 151631492Swollman execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); 151731492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 151831492Swollman pp->filters[LPF_OUTPUT]); 15191553Srgrimes exit(1); 15201553Srgrimes } 15211553Srgrimes (void) close(p[0]); /* close input side */ 15221553Srgrimes ofd = p[1]; /* use pipe for output */ 15231553Srgrimes } else { 15241553Srgrimes ofd = pfd; 15251553Srgrimes ofilter = 0; 15261553Srgrimes } 15271553Srgrimes} 15281553Srgrimes 152915648Sjoerg/* 153015648Sjoerg * Printer connected directly to the network 153115648Sjoerg * or to a terminal server on the net 153215648Sjoerg */ 153315648Sjoergstatic void 153478146Sgadopennet(const struct printer *pp) 153515648Sjoerg{ 153615648Sjoerg register int i; 153731492Swollman int resp; 153831492Swollman u_long port; 153931492Swollman char *ep; 154030407Sjoerg void (*savealrm)(int); 154115648Sjoerg 154231492Swollman port = strtoul(pp->lp, &ep, 0); 154338470Sbrian if (*ep != '@' || port > 65535) { 154431492Swollman syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 154531492Swollman pp->lp); 154615648Sjoerg exit(1); 154715648Sjoerg } 154831492Swollman ep++; 154915648Sjoerg 155015648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 155115648Sjoerg resp = -1; 155230407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 155331492Swollman alarm(pp->conn_timeout); 155431492Swollman pfd = getport(pp, ep, port); 155531020Sjoerg alarm(0); 155630407Sjoerg (void)signal(SIGALRM, savealrm); 155715648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 155815648Sjoerg resp = 1; 155915648Sjoerg else if (pfd >= 0) { 156015648Sjoerg /* 156115648Sjoerg * need to delay a bit for rs232 lines 156215648Sjoerg * to stabilize in case printer is 156315648Sjoerg * connected via a terminal server 156415648Sjoerg */ 156515648Sjoerg delay(500); 156615648Sjoerg break; 156715648Sjoerg } 156815648Sjoerg if (i == 1) { 156931492Swollman if (resp < 0) 157031492Swollman pstatus(pp, "waiting for %s to come up", 157131492Swollman pp->lp); 157231492Swollman else 157331492Swollman pstatus(pp, 157431492Swollman "waiting for access to printer on %s", 157531492Swollman pp->lp); 157615648Sjoerg } 157715648Sjoerg sleep(i); 157815648Sjoerg } 157931492Swollman pstatus(pp, "sending to %s port %d", ep, port); 158015648Sjoerg} 158115648Sjoerg 158215648Sjoerg/* 158315648Sjoerg * Printer is connected to an RS232 port on this host 158415648Sjoerg */ 158515648Sjoergstatic void 158678146Sgadopentty(const struct printer *pp) 158715648Sjoerg{ 158815648Sjoerg register int i; 158915648Sjoerg 159015648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 159131492Swollman pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 159215648Sjoerg if (pfd >= 0) { 159315648Sjoerg delay(500); 159415648Sjoerg break; 159515648Sjoerg } 159615648Sjoerg if (errno == ENOENT) { 159731492Swollman syslog(LOG_ERR, "%s: %m", pp->lp); 159815648Sjoerg exit(1); 159915648Sjoerg } 160015648Sjoerg if (i == 1) 160131492Swollman pstatus(pp, 160231492Swollman "waiting for %s to become ready (offline?)", 160331492Swollman pp->printer); 160415648Sjoerg sleep(i); 160515648Sjoerg } 160615648Sjoerg if (isatty(pfd)) 160731492Swollman setty(pp); 160831492Swollman pstatus(pp, "%s is ready and printing", pp->printer); 160915648Sjoerg} 161015648Sjoerg 161115648Sjoerg/* 161215648Sjoerg * Printer is on a remote host 161315648Sjoerg */ 161415648Sjoergstatic void 161578146Sgadopenrem(const struct printer *pp) 161615648Sjoerg{ 161731492Swollman register int i; 161827748Simp int resp; 161930407Sjoerg void (*savealrm)(int); 162015648Sjoerg 162115648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 162215648Sjoerg resp = -1; 162330407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 162431492Swollman alarm(pp->conn_timeout); 162531492Swollman pfd = getport(pp, pp->remote_host, 0); 162631020Sjoerg alarm(0); 162730407Sjoerg (void)signal(SIGALRM, savealrm); 162815648Sjoerg if (pfd >= 0) { 162931492Swollman if ((writel(pfd, "\2", pp->remote_queue, "\n", 163031492Swollman (char *)0) 163131492Swollman == 2 + strlen(pp->remote_queue)) 163231492Swollman && (resp = response(pp)) == 0) 163315648Sjoerg break; 163415648Sjoerg (void) close(pfd); 163515648Sjoerg } 163615648Sjoerg if (i == 1) { 163715648Sjoerg if (resp < 0) 163831492Swollman pstatus(pp, "waiting for %s to come up", 163931492Swollman pp->remote_host); 164015648Sjoerg else { 164131492Swollman pstatus(pp, 164231492Swollman "waiting for queue to be enabled on %s", 164331492Swollman pp->remote_host); 164415648Sjoerg i = 256; 164515648Sjoerg } 164615648Sjoerg } 164715648Sjoerg sleep(i); 164815648Sjoerg } 164931492Swollman pstatus(pp, "sending to %s", pp->remote_host); 165015648Sjoerg} 165115648Sjoerg 16521553Srgrimes/* 16531553Srgrimes * setup tty lines. 16541553Srgrimes */ 16551553Srgrimesstatic void 165678146Sgadsetty(const struct printer *pp) 16571553Srgrimes{ 165815032Ssef struct termios ttybuf; 16591553Srgrimes 16601553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 166131492Swollman syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 16621553Srgrimes exit(1); 16631553Srgrimes } 166415032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 166531492Swollman syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 16661553Srgrimes exit(1); 16671553Srgrimes } 166831492Swollman if (pp->baud_rate > 0) 166931492Swollman cfsetspeed(&ttybuf, pp->baud_rate); 167031492Swollman if (pp->mode_set) { 167131492Swollman char *s = strdup(pp->mode_set), *tmp; 167215032Ssef 167331492Swollman while ((tmp = strsep(&s, ",")) != NULL) { 167439084Swollman (void) msearch(tmp, &ttybuf); 16751553Srgrimes } 16761553Srgrimes } 167731492Swollman if (pp->mode_set != 0 || pp->baud_rate > 0) { 167815032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 167931492Swollman syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 16801553Srgrimes } 16811553Srgrimes } 16821553Srgrimes} 16831553Srgrimes 168427757Simp#ifdef __STDC__ 16851553Srgrimes#include <stdarg.h> 16861553Srgrimes#else 16871553Srgrimes#include <varargs.h> 16881553Srgrimes#endif 16891553Srgrimes 169015648Sjoergstatic void 169127757Simp#ifdef __STDC__ 169231492Swollmanpstatus(const struct printer *pp, const char *msg, ...) 16931553Srgrimes#else 169431492Swollmanpstatus(pp, msg, va_alist) 169531492Swollman const struct printer *pp; 16961553Srgrimes char *msg; 16971553Srgrimes va_dcl 16981553Srgrimes#endif 16991553Srgrimes{ 170031492Swollman int fd; 170131492Swollman char *buf; 17021553Srgrimes va_list ap; 170327757Simp#ifdef __STDC__ 17041553Srgrimes va_start(ap, msg); 17051553Srgrimes#else 17061553Srgrimes va_start(ap); 17071553Srgrimes#endif 17081553Srgrimes 17091553Srgrimes umask(0); 171031492Swollman fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 171131492Swollman if (fd < 0) { 171231492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 17131553Srgrimes exit(1); 17141553Srgrimes } 17151553Srgrimes ftruncate(fd, 0); 171631492Swollman vasprintf(&buf, msg, ap); 17171553Srgrimes va_end(ap); 171831492Swollman writel(fd, buf, "\n", (char *)0); 171931492Swollman close(fd); 172031492Swollman free(buf); 17211553Srgrimes} 172230407Sjoerg 172330407Sjoergvoid 172478146Sgadalarmhandler(int signo __unused) 172530407Sjoerg{ 172678146Sgad /* the signal is ignored */ 172778146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 172830407Sjoerg} 1729