printjob.c revision 80230
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 80230 2001-07-23 23:13:39Z 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 8080230Sgad#define DORETURN 0 /* dofork should return "can't fork" error */ 8180230Sgad#define DOABORT 1 /* dofork should just die if fork() 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 10980230Sgad/* these two are set from pp->daemon_user, but only if they are needed */ 11080230Sgadstatic char *daemon_uname; /* set from pwd->pw_name */ 11180230Sgadstatic int daemon_defgid; 11280230Sgad 1131553Srgrimesstatic char class[32]; /* classification field */ 11478300Sgadstatic char origin_host[MAXHOSTNAMELEN]; /* user's host machine */ 1151553Srgrimes /* indentation size in static characters */ 1168857Srgrimesstatic char indent[10] = "-i0"; 1171553Srgrimesstatic char jobname[100]; /* job or file name */ 1181553Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1191553Srgrimesstatic char logname[32]; /* user's login name */ 1201553Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1211553Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 12268664Sgad/* tempstderr is the filename used to catch stderr from exec-ing filters */ 12368664Sgadstatic char tempstderr[] = "errs.XXXXXXX"; 1241553Srgrimesstatic char width[10] = "-w"; /* page width in static characters */ 12524831Sbrian#define TFILENAME "fltXXXXXX" 12624831Sbrianstatic char tfile[] = TFILENAME; /* file name for filter output */ 1271553Srgrimes 12878146Sgadstatic void abortpr(int _signo); 12978146Sgadstatic void alarmhandler(int _signo); 13078146Sgadstatic void banner(struct printer *_pp, char *_name1, char *_name2); 13178146Sgadstatic int dofork(const struct printer *_pp, int _action); 13278146Sgadstatic int dropit(int _c); 13378146Sgadstatic void init(struct printer *_pp); 13478146Sgadstatic void openpr(const struct printer *_pp); 13578146Sgadstatic void opennet(const struct printer *_pp); 13678146Sgadstatic void opentty(const struct printer *_pp); 13778146Sgadstatic void openrem(const struct printer *pp); 13878146Sgadstatic int print(struct printer *_pp, int _format, char *_file); 13978146Sgadstatic int printit(struct printer *_pp, char *_file); 14079739Sgadstatic void pstatus(const struct printer *_pp, const char *_msg, ...) 14179739Sgad __printflike(2, 3); 14278146Sgadstatic char response(const struct printer *_pp); 14378146Sgadstatic void scan_out(struct printer *_pp, int _scfd, char *_scsp, 14478146Sgad int _dlm); 14578146Sgadstatic char *scnline(int _key, char *_p, int _c); 14678146Sgadstatic int sendfile(struct printer *_pp, int _type, char *_file, 14778146Sgad char _format); 14878146Sgadstatic int sendit(struct printer *_pp, char *_file); 14978146Sgadstatic void sendmail(struct printer *_pp, char *_user, int _bombed); 15078146Sgadstatic void setty(const struct printer *_pp); 1511553Srgrimes 1521553Srgrimesvoid 15378146Sgadprintjob(struct printer *pp) 1541553Srgrimes{ 1551553Srgrimes struct stat stb; 15668401Sgad register struct jobqueue *q, **qp; 15768401Sgad struct jobqueue **queue; 1581553Srgrimes register int i, nitems; 15968733Sgad off_t pidoff; 16068733Sgad int errcnt, jobcount, tempfd; 1611553Srgrimes 16268733Sgad jobcount = 0; 16331492Swollman init(pp); /* set up capabilities */ 16431492Swollman (void) write(1, "", 1); /* ack that daemon is started */ 1651553Srgrimes (void) close(2); /* set up log file */ 16631492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 16731492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1681553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1691553Srgrimes } 1701553Srgrimes setgid(getegid()); 1711553Srgrimes pid = getpid(); /* for use with lprm */ 1721553Srgrimes setpgrp(0, pid); 17379735Sgad 17479735Sgad /* 17579735Sgad * At initial lpd startup, printjob may be called with various 17679735Sgad * signal handlers in effect. After that initial startup, any 17779735Sgad * calls to printjob will have a *different* set of signal-handlers 17879735Sgad * in effect. Make sure all handlers are the ones we want. 17979735Sgad */ 18079735Sgad signal(SIGCHLD, SIG_DFL); 1811553Srgrimes signal(SIGHUP, abortpr); 1821553Srgrimes signal(SIGINT, abortpr); 1831553Srgrimes signal(SIGQUIT, abortpr); 1841553Srgrimes signal(SIGTERM, abortpr); 1851553Srgrimes 1861553Srgrimes /* 1871553Srgrimes * uses short form file names 1881553Srgrimes */ 18931492Swollman if (chdir(pp->spool_dir) < 0) { 19031492Swollman syslog(LOG_ERR, "%s: %m", pp->spool_dir); 1911553Srgrimes exit(1); 1921553Srgrimes } 19331492Swollman if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 1941553Srgrimes exit(0); /* printing disabled */ 19531492Swollman lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 19631492Swollman LOCK_FILE_MODE); 1971553Srgrimes if (lfd < 0) { 19831492Swollman if (errno == EWOULDBLOCK) /* active daemon present */ 19931492Swollman exit(0); 20031492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 2011553Srgrimes exit(1); 2021553Srgrimes } 20331492Swollman /* turn off non-blocking mode (was turned on for lock effects only) */ 20431492Swollman if (fcntl(lfd, F_SETFL, 0) < 0) { 20531492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 2061553Srgrimes exit(1); 2071553Srgrimes } 2081553Srgrimes ftruncate(lfd, 0); 2091553Srgrimes /* 2101553Srgrimes * write process id for others to know 2111553Srgrimes */ 2121553Srgrimes sprintf(line, "%u\n", pid); 2131553Srgrimes pidoff = i = strlen(line); 2141553Srgrimes if (write(lfd, line, i) != i) { 21531492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 2161553Srgrimes exit(1); 2171553Srgrimes } 2181553Srgrimes /* 2191553Srgrimes * search the spool directory for work and sort by queue order. 2201553Srgrimes */ 22131492Swollman if ((nitems = getq(pp, &queue)) < 0) { 22231492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 22331492Swollman pp->spool_dir); 2241553Srgrimes exit(1); 2251553Srgrimes } 2261553Srgrimes if (nitems == 0) /* no work to do */ 2271553Srgrimes exit(0); 22831492Swollman if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 22931492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 23031492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 23131492Swollman pp->lock_file); 2321553Srgrimes } 23368664Sgad 23468664Sgad /* create a file which will be used to hold stderr from filters */ 23568664Sgad if ((tempfd = mkstemp(tempstderr)) == -1) { 23668664Sgad syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 23768664Sgad tempstderr); 23868732Sgad exit(1); 23968664Sgad } 24068664Sgad if ((i = fchmod(tempfd, 0664)) == -1) { 24168664Sgad syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 24268664Sgad tempstderr); 24368732Sgad exit(1); 24468664Sgad } 24568664Sgad /* lpd doesn't need it to be open, it just needs it to exist */ 24668664Sgad close(tempfd); 24768664Sgad 24831492Swollman openpr(pp); /* open printer or remote */ 2491553Srgrimesagain: 2501553Srgrimes /* 2511553Srgrimes * we found something to do now do it -- 2521553Srgrimes * write the name of the current control file into the lock file 2531553Srgrimes * so the spool queue program can tell what we're working on 2541553Srgrimes */ 2551553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2561553Srgrimes q = *qp++; 25768401Sgad if (stat(q->job_cfname, &stb) < 0) 2581553Srgrimes continue; 25915648Sjoerg errcnt = 0; 2601553Srgrimes restart: 26115648Sjoerg (void) lseek(lfd, pidoff, 0); 26268401Sgad (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 2631553Srgrimes i = strlen(line); 2641553Srgrimes if (write(lfd, line, i) != i) 26531492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 26631492Swollman pp->lock_file); 26731492Swollman if (!pp->remote) 26868401Sgad i = printit(pp, q->job_cfname); 2691553Srgrimes else 27068401Sgad i = sendit(pp, q->job_cfname); 2711553Srgrimes /* 2721553Srgrimes * Check to see if we are supposed to stop printing or 2731553Srgrimes * if we are to rebuild the queue. 2741553Srgrimes */ 2751553Srgrimes if (fstat(lfd, &stb) == 0) { 2761553Srgrimes /* stop printing before starting next job? */ 27731492Swollman if (stb.st_mode & LFM_PRINT_DIS) 2781553Srgrimes goto done; 2791553Srgrimes /* rebuild queue (after lpc topq) */ 28031492Swollman if (stb.st_mode & LFM_RESET_QUE) { 28131492Swollman for (free(q); nitems--; free(q)) 2821553Srgrimes q = *qp++; 28331492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 28431492Swollman < 0) 2851553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 28631492Swollman pp->printer, pp->lock_file); 2871553Srgrimes break; 2881553Srgrimes } 2891553Srgrimes } 29068733Sgad if (i == OK) /* all files of this job printed */ 29168733Sgad jobcount++; 29215648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 29315648Sjoerg /* try reprinting the job */ 29431492Swollman syslog(LOG_INFO, "restarting %s", pp->printer); 2951553Srgrimes if (ofilter > 0) { 2961553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2971553Srgrimes (void) close(ofd); 29815648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2991553Srgrimes ; 30079735Sgad if (i < 0) 30179735Sgad syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m", 30279735Sgad pp->printer, ofilter); 3031553Srgrimes ofilter = 0; 3041553Srgrimes } 3051553Srgrimes (void) close(pfd); /* close printer */ 3061553Srgrimes if (ftruncate(lfd, pidoff) < 0) 30731492Swollman syslog(LOG_WARNING, "%s: %s: %m", 30831492Swollman pp->printer, pp->lock_file); 30931492Swollman openpr(pp); /* try to reopen printer */ 3101553Srgrimes goto restart; 31115648Sjoerg } else { 31231492Swollman syslog(LOG_WARNING, "%s: job could not be %s (%s)", 31331492Swollman pp->printer, 31431492Swollman pp->remote ? "sent to remote host" : "printed", 31568401Sgad q->job_cfname); 31615648Sjoerg if (i == REPRINT) { 31727748Simp /* ensure we don't attempt this job again */ 31868401Sgad (void) unlink(q->job_cfname); 31968401Sgad q->job_cfname[0] = 'd'; 32068401Sgad (void) unlink(q->job_cfname); 32115648Sjoerg if (logname[0]) 32231492Swollman sendmail(pp, logname, FATALERR); 32315648Sjoerg } 3241553Srgrimes } 3251553Srgrimes } 32631492Swollman free(queue); 3271553Srgrimes /* 3281553Srgrimes * search the spool directory for more work. 3291553Srgrimes */ 33031492Swollman if ((nitems = getq(pp, &queue)) < 0) { 33131492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 33231492Swollman pp->spool_dir); 3331553Srgrimes exit(1); 3341553Srgrimes } 3351553Srgrimes if (nitems == 0) { /* no more work to do */ 3361553Srgrimes done: 33768733Sgad if (jobcount > 0) { /* jobs actually printed */ 33831492Swollman if (!pp->no_formfeed && !pp->tof) 33931492Swollman (void) write(ofd, pp->form_feed, 34031492Swollman strlen(pp->form_feed)); 34131492Swollman if (pp->trailer != NULL) /* output trailer */ 34231492Swollman (void) write(ofd, pp->trailer, 34331492Swollman strlen(pp->trailer)); 3441553Srgrimes } 34519202Simp (void) close(ofd); 34619202Simp (void) wait(NULL); 34768664Sgad (void) unlink(tempstderr); 3481553Srgrimes exit(0); 3491553Srgrimes } 3501553Srgrimes goto again; 3511553Srgrimes} 3521553Srgrimes 3531553Srgrimeschar fonts[4][50]; /* fonts for troff */ 3541553Srgrimes 3551553Srgrimeschar ifonts[4][40] = { 3561553Srgrimes _PATH_VFONTR, 3571553Srgrimes _PATH_VFONTI, 3581553Srgrimes _PATH_VFONTB, 3591553Srgrimes _PATH_VFONTS, 3601553Srgrimes}; 3611553Srgrimes 3621553Srgrimes/* 3631553Srgrimes * The remaining part is the reading of the control file (cf) 3641553Srgrimes * and performing the various actions. 3651553Srgrimes */ 3661553Srgrimesstatic int 36778146Sgadprintit(struct printer *pp, char *file) 3681553Srgrimes{ 3691553Srgrimes register int i; 37068734Sgad char *cp; 37168734Sgad int bombed, didignorehdr; 3721553Srgrimes 37368734Sgad bombed = OK; 37468734Sgad didignorehdr = 0; 3751553Srgrimes /* 3761553Srgrimes * open control file; ignore if no longer there. 3771553Srgrimes */ 3781553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 37931492Swollman syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 3801553Srgrimes return(OK); 3811553Srgrimes } 3821553Srgrimes /* 3831553Srgrimes * Reset troff fonts. 3841553Srgrimes */ 3851553Srgrimes for (i = 0; i < 4; i++) 3861553Srgrimes strcpy(fonts[i], ifonts[i]); 38731492Swollman sprintf(&width[2], "%ld", pp->page_width); 3881553Srgrimes strcpy(indent+2, "0"); 3891553Srgrimes 39068253Sgad /* initialize job-specific count of datafiles processed */ 39168253Sgad job_dfcnt = 0; 39268253Sgad 3931553Srgrimes /* 3941553Srgrimes * read the control file for work to do 3951553Srgrimes * 3961553Srgrimes * file format -- first character in the line is a command 3971553Srgrimes * rest of the line is the argument. 3981553Srgrimes * valid commands are: 3991553Srgrimes * 4001553Srgrimes * S -- "stat info" for symbolic link protection 4011553Srgrimes * J -- "job name" on banner page 4021553Srgrimes * C -- "class name" on banner page 4031553Srgrimes * L -- "literal" user's name to print on banner 4041553Srgrimes * T -- "title" for pr 4051553Srgrimes * H -- "host name" of machine where lpr was done 4061553Srgrimes * P -- "person" user's login name 4071553Srgrimes * I -- "indent" amount to indent output 40815648Sjoerg * R -- laser dpi "resolution" 4091553Srgrimes * f -- "file name" name of text file to print 4101553Srgrimes * l -- "file name" text file with control chars 4111553Srgrimes * p -- "file name" text file to print with pr(1) 4121553Srgrimes * t -- "file name" troff(1) file to print 4131553Srgrimes * n -- "file name" ditroff(1) file to print 4141553Srgrimes * d -- "file name" dvi file to print 4151553Srgrimes * g -- "file name" plot(1G) file to print 4161553Srgrimes * v -- "file name" plain raster file to print 4171553Srgrimes * c -- "file name" cifplot file to print 4181553Srgrimes * 1 -- "R font file" for troff 4191553Srgrimes * 2 -- "I font file" for troff 4201553Srgrimes * 3 -- "B font file" for troff 4211553Srgrimes * 4 -- "S font file" for troff 4221553Srgrimes * N -- "name" of file (used by lpq) 4231553Srgrimes * U -- "unlink" name of file to remove 4241553Srgrimes * (after we print it. (Pass 2 only)). 4251553Srgrimes * M -- "mail" to user when done printing 42653956Sache * Z -- "locale" for pr 4271553Srgrimes * 4281553Srgrimes * getline reads a line and expands tabs to blanks 4291553Srgrimes */ 4301553Srgrimes 4311553Srgrimes /* pass 1 */ 4321553Srgrimes 4331553Srgrimes while (getline(cfp)) 4341553Srgrimes switch (line[0]) { 4351553Srgrimes case 'H': 43678300Sgad strlcpy(origin_host, line + 1, sizeof(origin_host)); 43727748Simp if (class[0] == '\0') { 43880133Sgad strlcpy(class, line+1, sizeof(class)); 43927748Simp } 4401553Srgrimes continue; 4411553Srgrimes 4421553Srgrimes case 'P': 44380133Sgad strlcpy(logname, line + 1, sizeof(logname)); 44431492Swollman if (pp->restricted) { /* restricted */ 4451553Srgrimes if (getpwnam(logname) == NULL) { 4461553Srgrimes bombed = NOACCT; 44731492Swollman sendmail(pp, line+1, bombed); 4481553Srgrimes goto pass2; 4491553Srgrimes } 4501553Srgrimes } 4511553Srgrimes continue; 4521553Srgrimes 4531553Srgrimes case 'S': 4541553Srgrimes cp = line+1; 4551553Srgrimes i = 0; 4561553Srgrimes while (*cp >= '0' && *cp <= '9') 4571553Srgrimes i = i * 10 + (*cp++ - '0'); 4581553Srgrimes fdev = i; 4591553Srgrimes cp++; 4601553Srgrimes i = 0; 4611553Srgrimes while (*cp >= '0' && *cp <= '9') 4621553Srgrimes i = i * 10 + (*cp++ - '0'); 4631553Srgrimes fino = i; 4641553Srgrimes continue; 4651553Srgrimes 4661553Srgrimes case 'J': 46727748Simp if (line[1] != '\0') { 46880133Sgad strlcpy(jobname, line + 1, sizeof(jobname)); 46927748Simp } else 4701553Srgrimes strcpy(jobname, " "); 4711553Srgrimes continue; 4721553Srgrimes 4731553Srgrimes case 'C': 4741553Srgrimes if (line[1] != '\0') 47580133Sgad strlcpy(class, line + 1, sizeof(class)); 47680133Sgad else if (class[0] == '\0') { 47780133Sgad /* XXX - why call gethostname instead of 47880133Sgad * just strlcpy'ing local_host? */ 4791553Srgrimes gethostname(class, sizeof(class)); 48080133Sgad class[sizeof(class) - 1] = '\0'; 48180133Sgad } 4821553Srgrimes continue; 4831553Srgrimes 4841553Srgrimes case 'T': /* header title for pr */ 48580133Sgad strlcpy(title, line + 1, sizeof(title)); 4861553Srgrimes continue; 4871553Srgrimes 4881553Srgrimes case 'L': /* identification line */ 48931492Swollman if (!pp->no_header && !pp->header_last) 49031492Swollman banner(pp, line+1, jobname); 4911553Srgrimes continue; 4921553Srgrimes 4931553Srgrimes case '1': /* troff fonts */ 4941553Srgrimes case '2': 4951553Srgrimes case '3': 4961553Srgrimes case '4': 49727748Simp if (line[1] != '\0') { 49880133Sgad strlcpy(fonts[line[0]-'1'], line + 1, 49980133Sgad (size_t)50); 50027748Simp } 5011553Srgrimes continue; 5021553Srgrimes 5031553Srgrimes case 'W': /* page width */ 50480133Sgad strlcpy(width+2, line + 1, sizeof(width) - 2); 5051553Srgrimes continue; 5061553Srgrimes 5071553Srgrimes case 'I': /* indent amount */ 50880133Sgad strlcpy(indent+2, line + 1, sizeof(indent) - 2); 5091553Srgrimes continue; 5101553Srgrimes 51153956Sache case 'Z': /* locale for pr */ 51280133Sgad strlcpy(locale, line + 1, sizeof(locale)); 51353956Sache locale[sizeof(locale) - 1] = '\0'; 51453956Sache continue; 51553956Sache 5161553Srgrimes default: /* some file to print */ 51768467Sgad /* only lowercase cmd-codes include a file-to-print */ 51868467Sgad if ((line[0] < 'a') || (line[0] > 'z')) { 51968467Sgad /* ignore any other lines */ 52068467Sgad if (lflag <= 1) 52168467Sgad continue; 52268467Sgad if (!didignorehdr) { 52368467Sgad syslog(LOG_INFO, "%s: in %s :", 52468467Sgad pp->printer, file); 52568467Sgad didignorehdr = 1; 52668467Sgad } 52768467Sgad syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 52868467Sgad pp->printer, line[0], &line[1]); 52968467Sgad continue; 53068467Sgad } 53168467Sgad i = print(pp, line[0], line+1); 53268467Sgad switch (i) { 5331553Srgrimes case ERROR: 5341553Srgrimes if (bombed == OK) 5351553Srgrimes bombed = FATALERR; 5361553Srgrimes break; 5371553Srgrimes case REPRINT: 5381553Srgrimes (void) fclose(cfp); 5391553Srgrimes return(REPRINT); 5401553Srgrimes case FILTERERR: 5411553Srgrimes case ACCESS: 5421553Srgrimes bombed = i; 54331492Swollman sendmail(pp, logname, bombed); 5441553Srgrimes } 5451553Srgrimes title[0] = '\0'; 5461553Srgrimes continue; 5471553Srgrimes 5481553Srgrimes case 'N': 5491553Srgrimes case 'U': 5501553Srgrimes case 'M': 55115648Sjoerg case 'R': 5521553Srgrimes continue; 5531553Srgrimes } 5541553Srgrimes 5551553Srgrimes /* pass 2 */ 5561553Srgrimes 5571553Srgrimespass2: 5581553Srgrimes fseek(cfp, 0L, 0); 5591553Srgrimes while (getline(cfp)) 5601553Srgrimes switch (line[0]) { 5611553Srgrimes case 'L': /* identification line */ 56231492Swollman if (!pp->no_header && pp->header_last) 56331492Swollman banner(pp, line+1, jobname); 5641553Srgrimes continue; 5651553Srgrimes 5661553Srgrimes case 'M': 5671553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 56831492Swollman sendmail(pp, line+1, bombed); 5691553Srgrimes continue; 5701553Srgrimes 5711553Srgrimes case 'U': 57227748Simp if (strchr(line+1, '/')) 57327748Simp continue; 5741553Srgrimes (void) unlink(line+1); 5751553Srgrimes } 5761553Srgrimes /* 5771553Srgrimes * clean-up in case another control file exists 5781553Srgrimes */ 5791553Srgrimes (void) fclose(cfp); 5801553Srgrimes (void) unlink(file); 5811553Srgrimes return(bombed == OK ? OK : ERROR); 5821553Srgrimes} 5831553Srgrimes 5841553Srgrimes/* 5851553Srgrimes * Print a file. 5861553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 5871553Srgrimes * Return -1 if a non-recoverable error occured, 5881553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 5891553Srgrimes * 1 if we should try to reprint this job and 5901553Srgrimes * 0 if all is well. 5911553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5921553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5931553Srgrimes */ 5941553Srgrimesstatic int 59578146Sgadprint(struct printer *pp, int format, char *file) 5961553Srgrimes{ 59753956Sache register int n, i; 5981553Srgrimes register char *prog; 59931492Swollman int fi, fo; 6001553Srgrimes FILE *fp; 6011553Srgrimes char *av[15], buf[BUFSIZ]; 60268734Sgad int pid, p[2], stopped; 6031553Srgrimes union wait status; 6041553Srgrimes struct stat stb; 6051553Srgrimes 60668467Sgad if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 60768467Sgad syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 60868467Sgad pp->printer, file, format); 6091553Srgrimes return(ERROR); 61068467Sgad } 6111553Srgrimes /* 6121553Srgrimes * Check to see if data file is a symbolic link. If so, it should 6131553Srgrimes * still point to the same file or someone is trying to print 6141553Srgrimes * something he shouldn't. 6151553Srgrimes */ 6161553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 6171553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 6181553Srgrimes return(ACCESS); 61968253Sgad 62068253Sgad job_dfcnt++; /* increment datafile counter for this job */ 62168734Sgad stopped = 0; /* output filter is not stopped */ 62268253Sgad 62368253Sgad /* everything seems OK, start it up */ 62431492Swollman if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 62531492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 62631492Swollman pp->tof = 1; 6271553Srgrimes } 62831492Swollman if (pp->filters[LPF_INPUT] == NULL 62931492Swollman && (format == 'f' || format == 'l')) { 63031492Swollman pp->tof = 0; 6311553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 6321553Srgrimes if (write(ofd, buf, n) != n) { 6331553Srgrimes (void) close(fi); 6341553Srgrimes return(REPRINT); 6351553Srgrimes } 6361553Srgrimes (void) close(fi); 6371553Srgrimes return(OK); 6381553Srgrimes } 6391553Srgrimes switch (format) { 6401553Srgrimes case 'p': /* print file using 'pr' */ 64131492Swollman if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 6421553Srgrimes prog = _PATH_PR; 64353956Sache i = 0; 64453956Sache av[i++] = "pr"; 64553956Sache av[i++] = width; 64653956Sache av[i++] = length; 64753956Sache av[i++] = "-h"; 64853956Sache av[i++] = *title ? title : " "; 64953956Sache av[i++] = "-L"; 65053956Sache av[i++] = *locale ? locale : "C"; 65153956Sache av[i++] = "-F"; 65253956Sache av[i] = 0; 6531553Srgrimes fo = ofd; 6541553Srgrimes goto start; 6551553Srgrimes } 6561553Srgrimes pipe(p); 65731492Swollman if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 6581553Srgrimes dup2(fi, 0); /* file is stdin */ 6591553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 6608094Sjkh closelog(); 66131492Swollman closeallfds(3); 6621553Srgrimes execl(_PATH_PR, "pr", width, length, 66353956Sache "-h", *title ? title : " ", 66453956Sache "-L", *locale ? locale : "C", 66579452Sbrian "-F", (char *)0); 6661553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 6671553Srgrimes exit(2); 6681553Srgrimes } 6691553Srgrimes (void) close(p[1]); /* close output side */ 6701553Srgrimes (void) close(fi); 6711553Srgrimes if (prchild < 0) { 6721553Srgrimes prchild = 0; 6731553Srgrimes (void) close(p[0]); 6741553Srgrimes return(ERROR); 6751553Srgrimes } 6761553Srgrimes fi = p[0]; /* use pipe for input */ 6771553Srgrimes case 'f': /* print plain text file */ 67831492Swollman prog = pp->filters[LPF_INPUT]; 6791553Srgrimes av[1] = width; 6801553Srgrimes av[2] = length; 6811553Srgrimes av[3] = indent; 6821553Srgrimes n = 4; 6831553Srgrimes break; 6841553Srgrimes case 'l': /* like 'f' but pass control characters */ 68531492Swollman prog = pp->filters[LPF_INPUT]; 6861553Srgrimes av[1] = "-c"; 6871553Srgrimes av[2] = width; 6881553Srgrimes av[3] = length; 6891553Srgrimes av[4] = indent; 6901553Srgrimes n = 5; 6911553Srgrimes break; 6921553Srgrimes case 'r': /* print a fortran text file */ 69331492Swollman prog = pp->filters[LPF_FORTRAN]; 6941553Srgrimes av[1] = width; 6951553Srgrimes av[2] = length; 6961553Srgrimes n = 3; 6971553Srgrimes break; 6981553Srgrimes case 't': /* print troff output */ 6991553Srgrimes case 'n': /* print ditroff output */ 7001553Srgrimes case 'd': /* print tex output */ 7011553Srgrimes (void) unlink(".railmag"); 7021553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 70331492Swollman syslog(LOG_ERR, "%s: cannot create .railmag", 70431492Swollman pp->printer); 7051553Srgrimes (void) unlink(".railmag"); 7061553Srgrimes } else { 7071553Srgrimes for (n = 0; n < 4; n++) { 7081553Srgrimes if (fonts[n][0] != '/') 7091553Srgrimes (void) write(fo, _PATH_VFONT, 7101553Srgrimes sizeof(_PATH_VFONT) - 1); 7111553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 7121553Srgrimes (void) write(fo, "\n", 1); 7131553Srgrimes } 7141553Srgrimes (void) close(fo); 7151553Srgrimes } 71631492Swollman prog = (format == 't') ? pp->filters[LPF_TROFF] 71731492Swollman : ((format == 'n') ? pp->filters[LPF_DITROFF] 71831492Swollman : pp->filters[LPF_DVI]); 7191553Srgrimes av[1] = pxwidth; 7201553Srgrimes av[2] = pxlength; 7211553Srgrimes n = 3; 7221553Srgrimes break; 7231553Srgrimes case 'c': /* print cifplot output */ 72431492Swollman prog = pp->filters[LPF_CIFPLOT]; 7251553Srgrimes av[1] = pxwidth; 7261553Srgrimes av[2] = pxlength; 7271553Srgrimes n = 3; 7281553Srgrimes break; 7291553Srgrimes case 'g': /* print plot(1G) output */ 73031492Swollman prog = pp->filters[LPF_GRAPH]; 7311553Srgrimes av[1] = pxwidth; 7321553Srgrimes av[2] = pxlength; 7331553Srgrimes n = 3; 7341553Srgrimes break; 7351553Srgrimes case 'v': /* print raster output */ 73631492Swollman prog = pp->filters[LPF_RASTER]; 7371553Srgrimes av[1] = pxwidth; 7381553Srgrimes av[2] = pxlength; 7391553Srgrimes n = 3; 7401553Srgrimes break; 7411553Srgrimes default: 7421553Srgrimes (void) close(fi); 7431553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 74431492Swollman pp->printer, format); 7451553Srgrimes return(ERROR); 7461553Srgrimes } 74715648Sjoerg if (prog == NULL) { 74815648Sjoerg (void) close(fi); 74915648Sjoerg syslog(LOG_ERR, 75015648Sjoerg "%s: no filter found in printcap for format character '%c'", 75131492Swollman pp->printer, format); 75215648Sjoerg return(ERROR); 75315648Sjoerg } 75427635Simp if ((av[0] = strrchr(prog, '/')) != NULL) 7551553Srgrimes av[0]++; 7561553Srgrimes else 7571553Srgrimes av[0] = prog; 7581553Srgrimes av[n++] = "-n"; 7591553Srgrimes av[n++] = logname; 7601553Srgrimes av[n++] = "-h"; 76178300Sgad av[n++] = origin_host; 76231492Swollman av[n++] = pp->acct_file; 7631553Srgrimes av[n] = 0; 7641553Srgrimes fo = pfd; 7651553Srgrimes if (ofilter > 0) { /* stop output filter */ 7661553Srgrimes write(ofd, "\031\1", 2); 7671553Srgrimes while ((pid = 7681553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 7691553Srgrimes ; 77079735Sgad if (pid < 0) 77179735Sgad syslog(LOG_WARNING, "%s: after stopping 'of', wait3() returned: %m", 77279735Sgad pp->printer); 77379735Sgad else if (status.w_stopval != WSTOPPED) { 7741553Srgrimes (void) close(fi); 77515648Sjoerg syslog(LOG_WARNING, 77631492Swollman "%s: output filter died " 77779735Sgad "(pid=%d retcode=%d termsig=%d)", 77879735Sgad pp->printer, ofilter, status.w_retcode, 77931492Swollman status.w_termsig); 7801553Srgrimes return(REPRINT); 7811553Srgrimes } 7821553Srgrimes stopped++; 7831553Srgrimes } 7841553Srgrimesstart: 78531492Swollman if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 7861553Srgrimes dup2(fi, 0); 7871553Srgrimes dup2(fo, 1); 78868664Sgad /* setup stderr for the filter (child process) 78968664Sgad * so it goes to our temporary errors file */ 79068664Sgad n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 7911553Srgrimes if (n >= 0) 7921553Srgrimes dup2(n, 2); 7938094Sjkh closelog(); 79431492Swollman closeallfds(3); 7951553Srgrimes execv(prog, av); 7961553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 7971553Srgrimes exit(2); 7981553Srgrimes } 7991553Srgrimes (void) close(fi); 8001553Srgrimes if (child < 0) 8011553Srgrimes status.w_retcode = 100; 80279735Sgad else { 8031553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 8041553Srgrimes ; 80579735Sgad if (pid < 0) { 80679735Sgad status.w_retcode = 100; 80779735Sgad syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 80879735Sgad pp->printer, prog); 80979735Sgad } 81079735Sgad } 8111553Srgrimes child = 0; 8121553Srgrimes prchild = 0; 8131553Srgrimes if (stopped) { /* restart output filter */ 8141553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 8151553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 8161553Srgrimes exit(1); 8171553Srgrimes } 8181553Srgrimes } 81931492Swollman pp->tof = 0; 8201553Srgrimes 82168664Sgad /* Copy the filter's output to "lf" logfile */ 82268664Sgad if ((fp = fopen(tempstderr, "r"))) { 8231553Srgrimes while (fgets(buf, sizeof(buf), fp)) 8241553Srgrimes fputs(buf, stderr); 8251553Srgrimes fclose(fp); 8261553Srgrimes } 8271553Srgrimes 8281553Srgrimes if (!WIFEXITED(status)) { 82915648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 83031492Swollman pp->printer, format, status.w_termsig); 8311553Srgrimes return(ERROR); 8321553Srgrimes } 8331553Srgrimes switch (status.w_retcode) { 8341553Srgrimes case 0: 83531492Swollman pp->tof = 1; 8361553Srgrimes return(OK); 8371553Srgrimes case 1: 8381553Srgrimes return(REPRINT); 83915648Sjoerg case 2: 84015648Sjoerg return(ERROR); 8411553Srgrimes default: 84215648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 84331492Swollman pp->printer, format, status.w_retcode); 84415648Sjoerg return(FILTERERR); 8451553Srgrimes } 8461553Srgrimes} 8471553Srgrimes 8481553Srgrimes/* 8491553Srgrimes * Send the daemon control file (cf) and any data files. 8501553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 8511553Srgrimes * 0 if all is well. 8521553Srgrimes */ 8531553Srgrimesstatic int 85478146Sgadsendit(struct printer *pp, char *file) 8551553Srgrimes{ 8561553Srgrimes register int i, err = OK; 8571553Srgrimes char *cp, last[BUFSIZ]; 8581553Srgrimes 8591553Srgrimes /* 8601553Srgrimes * open control file 8611553Srgrimes */ 8621553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 8631553Srgrimes return(OK); 86468253Sgad 86568253Sgad /* initialize job-specific count of datafiles processed */ 86668253Sgad job_dfcnt = 0; 86768253Sgad 8681553Srgrimes /* 8691553Srgrimes * read the control file for work to do 8701553Srgrimes * 8711553Srgrimes * file format -- first character in the line is a command 8721553Srgrimes * rest of the line is the argument. 8731553Srgrimes * commands of interest are: 8741553Srgrimes * 8751553Srgrimes * a-z -- "file name" name of file to print 8761553Srgrimes * U -- "unlink" name of file to remove 8771553Srgrimes * (after we print it. (Pass 2 only)). 8781553Srgrimes */ 8791553Srgrimes 8801553Srgrimes /* 8811553Srgrimes * pass 1 8821553Srgrimes */ 8831553Srgrimes while (getline(cfp)) { 8841553Srgrimes again: 8851553Srgrimes if (line[0] == 'S') { 8861553Srgrimes cp = line+1; 8871553Srgrimes i = 0; 8881553Srgrimes while (*cp >= '0' && *cp <= '9') 8891553Srgrimes i = i * 10 + (*cp++ - '0'); 8901553Srgrimes fdev = i; 8911553Srgrimes cp++; 8921553Srgrimes i = 0; 8931553Srgrimes while (*cp >= '0' && *cp <= '9') 8941553Srgrimes i = i * 10 + (*cp++ - '0'); 8951553Srgrimes fino = i; 89624831Sbrian } else if (line[0] == 'H') { 89778300Sgad strlcpy(origin_host, line + 1, sizeof(origin_host)); 89868343Sgad if (class[0] == '\0') { 89980133Sgad strlcpy(class, line + 1, sizeof(class)); 90068343Sgad } 90124831Sbrian } else if (line[0] == 'P') { 90280133Sgad strlcpy(logname, line + 1, sizeof(logname)); 90331492Swollman if (pp->restricted) { /* restricted */ 90424831Sbrian if (getpwnam(logname) == NULL) { 90531492Swollman sendmail(pp, line+1, NOACCT); 90624831Sbrian err = ERROR; 90724831Sbrian break; 90824831Sbrian } 90924831Sbrian } 91024831Sbrian } else if (line[0] == 'I') { 91180133Sgad strlcpy(indent+2, line + 1, sizeof(indent) - 2); 91224831Sbrian } else if (line[0] >= 'a' && line[0] <= 'z') { 9131553Srgrimes strcpy(last, line); 91431492Swollman while ((i = getline(cfp)) != 0) 9151553Srgrimes if (strcmp(last, line)) 9161553Srgrimes break; 91731492Swollman switch (sendfile(pp, '\3', last+1, *last)) { 9181553Srgrimes case OK: 9191553Srgrimes if (i) 9201553Srgrimes goto again; 9211553Srgrimes break; 9221553Srgrimes case REPRINT: 9231553Srgrimes (void) fclose(cfp); 9241553Srgrimes return(REPRINT); 9251553Srgrimes case ACCESS: 92631492Swollman sendmail(pp, logname, ACCESS); 9271553Srgrimes case ERROR: 9281553Srgrimes err = ERROR; 9291553Srgrimes } 9301553Srgrimes break; 9311553Srgrimes } 9321553Srgrimes } 93331492Swollman if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 9341553Srgrimes (void) fclose(cfp); 9351553Srgrimes return(REPRINT); 9361553Srgrimes } 9371553Srgrimes /* 9381553Srgrimes * pass 2 9391553Srgrimes */ 9401553Srgrimes fseek(cfp, 0L, 0); 9411553Srgrimes while (getline(cfp)) 94227748Simp if (line[0] == 'U' && !strchr(line+1, '/')) 9431553Srgrimes (void) unlink(line+1); 9441553Srgrimes /* 9451553Srgrimes * clean-up in case another control file exists 9461553Srgrimes */ 9471553Srgrimes (void) fclose(cfp); 9481553Srgrimes (void) unlink(file); 9491553Srgrimes return(err); 9501553Srgrimes} 9511553Srgrimes 9521553Srgrimes/* 9531553Srgrimes * Send a data file to the remote machine and spool it. 9541553Srgrimes * Return positive if we should try resending. 9551553Srgrimes */ 9561553Srgrimesstatic int 95778146Sgadsendfile(struct printer *pp, int type, char *file, char format) 9581553Srgrimes{ 9591553Srgrimes register int f, i, amt; 9601553Srgrimes struct stat stb; 96168664Sgad FILE *fp; 9621553Srgrimes char buf[BUFSIZ]; 96374124Sgad int closedpr, resp, sizerr, statrc; 9641553Srgrimes 96574124Sgad statrc = lstat(file, &stb); 96674124Sgad if (statrc < 0) { 96774124Sgad syslog(LOG_ERR, "%s: error from lstat(%s): %m", 96874124Sgad pp->printer, file); 9691553Srgrimes return(ERROR); 97074124Sgad } 97174124Sgad f = open(file, O_RDONLY); 97274124Sgad if (f < 0) { 97374124Sgad syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 97474124Sgad pp->printer, file); 97574124Sgad return(ERROR); 97674124Sgad } 9771553Srgrimes /* 9781553Srgrimes * Check to see if data file is a symbolic link. If so, it should 9791553Srgrimes * still point to the same file or someone is trying to print something 9801553Srgrimes * he shouldn't. 9811553Srgrimes */ 9821553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 9831553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 9841553Srgrimes return(ACCESS); 98524831Sbrian 98668253Sgad job_dfcnt++; /* increment datafile counter for this job */ 98768253Sgad 98868253Sgad /* everything seems OK, start it up */ 98924831Sbrian sizerr = 0; 99024831Sbrian closedpr = 0; 99124831Sbrian if (type == '\3') { 99231492Swollman if (pp->filters[LPF_INPUT]) { 99324831Sbrian /* 99474124Sgad * We're sending something with an ifilter. We have to 99574124Sgad * run the ifilter and store the output as a temporary 99674124Sgad * spool file (tfile...), because the protocol requires 99774124Sgad * us to send the file size before we start sending any 99874124Sgad * of the data. 99924831Sbrian */ 100024831Sbrian char *av[15]; 100124831Sbrian int n; 100224831Sbrian int ifilter; 100331492Swollman union wait status; /* XXX */ 100424831Sbrian 100524831Sbrian strcpy(tfile,TFILENAME); 100624831Sbrian if ((tfd = mkstemp(tfile)) == -1) { 100724831Sbrian syslog(LOG_ERR, "mkstemp: %m"); 100824831Sbrian return(ERROR); 100924831Sbrian } 101031492Swollman if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 101131492Swollman av[0] = pp->filters[LPF_INPUT]; 101224831Sbrian else 101324831Sbrian av[0]++; 101424831Sbrian if (format == 'l') 101524831Sbrian av[n=1] = "-c"; 101624831Sbrian else 101724831Sbrian n = 0; 101824831Sbrian av[++n] = width; 101924831Sbrian av[++n] = length; 102024831Sbrian av[++n] = indent; 102124831Sbrian av[++n] = "-n"; 102224831Sbrian av[++n] = logname; 102324831Sbrian av[++n] = "-h"; 102478300Sgad av[++n] = origin_host; 102531492Swollman av[++n] = pp->acct_file; 102624831Sbrian av[++n] = 0; 102731492Swollman if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 102824831Sbrian dup2(f, 0); 102924831Sbrian dup2(tfd, 1); 103068664Sgad /* setup stderr for the filter (child process) 103168664Sgad * so it goes to our temporary errors file */ 103268664Sgad n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 103324831Sbrian if (n >= 0) 103424831Sbrian dup2(n, 2); 103524831Sbrian closelog(); 103631492Swollman closeallfds(3); 103731492Swollman execv(pp->filters[LPF_INPUT], av); 103831492Swollman syslog(LOG_ERR, "cannot execv %s", 103931492Swollman pp->filters[LPF_INPUT]); 104024831Sbrian exit(2); 104124831Sbrian } 104224831Sbrian (void) close(f); 104324831Sbrian if (ifilter < 0) 104424831Sbrian status.w_retcode = 100; 104579735Sgad else { 104624831Sbrian while ((pid = wait((int *)&status)) > 0 && 104724831Sbrian pid != ifilter) 104824831Sbrian ; 104979735Sgad if (pid < 0) { 105079735Sgad status.w_retcode = 100; 105179735Sgad syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 105279735Sgad pp->printer, pp->filters[LPF_INPUT]); 105379735Sgad } 105479735Sgad } 105568664Sgad /* Copy the filter's output to "lf" logfile */ 105668664Sgad if ((fp = fopen(tempstderr, "r"))) { 105768664Sgad while (fgets(buf, sizeof(buf), fp)) 105868664Sgad fputs(buf, stderr); 105968664Sgad fclose(fp); 106068664Sgad } 106168664Sgad /* process the return-code from the filter */ 106224831Sbrian switch (status.w_retcode) { 106324831Sbrian case 0: 106424831Sbrian break; 106524831Sbrian case 1: 106624831Sbrian unlink(tfile); 106724831Sbrian return(REPRINT); 106824831Sbrian case 2: 106924831Sbrian unlink(tfile); 107024831Sbrian return(ERROR); 107124831Sbrian default: 107224831Sbrian syslog(LOG_WARNING, "%s: filter '%c' exited" 107324831Sbrian " (retcode=%d)", 107431492Swollman pp->printer, format, status.w_retcode); 107524831Sbrian unlink(tfile); 107624831Sbrian return(FILTERERR); 107724831Sbrian } 107874124Sgad statrc = fstat(tfd, &stb); /* to find size of tfile */ 107974124Sgad if (statrc < 0) { 108074124Sgad syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m", 108174124Sgad pp->printer, tfile); 108224831Sbrian return(ERROR); 108374124Sgad } 108424831Sbrian f = tfd; 108524831Sbrian lseek(f,0,SEEK_SET); 108624831Sbrian } else if (ofilter) { 108724831Sbrian /* 108824831Sbrian * We're sending something with an ofilter, we have to 108924831Sbrian * store the output as a temporary file (tfile)... the 109024831Sbrian * protocol requires us to send the file size 109124831Sbrian */ 109224831Sbrian int i; 109324831Sbrian for (i = 0; i < stb.st_size; i += BUFSIZ) { 109424831Sbrian amt = BUFSIZ; 109524831Sbrian if (i + amt > stb.st_size) 109624831Sbrian amt = stb.st_size - i; 109724831Sbrian if (sizerr == 0 && read(f, buf, amt) != amt) { 109824831Sbrian sizerr = 1; 109924831Sbrian break; 110024831Sbrian } 110124831Sbrian if (write(ofd, buf, amt) != amt) { 110224831Sbrian (void) close(f); 110324831Sbrian return(REPRINT); 110424831Sbrian } 110524831Sbrian } 110624831Sbrian close(ofd); 110724831Sbrian close(f); 110824831Sbrian while ((i = wait(NULL)) > 0 && i != ofilter) 110924831Sbrian ; 111079735Sgad if (i < 0) 111179735Sgad syslog(LOG_WARNING, "%s: after closing 'of', wait() returned: %m", 111279735Sgad pp->printer); 111324831Sbrian ofilter = 0; 111474124Sgad statrc = fstat(tfd, &stb); /* to find size of tfile */ 111574124Sgad if (statrc < 0) { 111674124Sgad syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m", 111774124Sgad pp->printer, tfile); 111831492Swollman openpr(pp); 111924831Sbrian return(ERROR); 112024831Sbrian } 112124831Sbrian f = tfd; 112224831Sbrian lseek(f,0,SEEK_SET); 112324831Sbrian closedpr = 1; 112424831Sbrian } 112524831Sbrian } 112624831Sbrian 11271553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 11281553Srgrimes amt = strlen(buf); 11291553Srgrimes for (i = 0; ; i++) { 11301553Srgrimes if (write(pfd, buf, amt) != amt || 113131492Swollman (resp = response(pp)) < 0 || resp == '\1') { 11321553Srgrimes (void) close(f); 113324831Sbrian if (tfd != -1 && type == '\3') { 113424831Sbrian tfd = -1; 113524831Sbrian unlink(tfile); 113624831Sbrian if (closedpr) 113731492Swollman openpr(pp); 113824831Sbrian } 11391553Srgrimes return(REPRINT); 11401553Srgrimes } else if (resp == '\0') 11411553Srgrimes break; 11421553Srgrimes if (i == 0) 114331492Swollman pstatus(pp, 114431492Swollman "no space on remote; waiting for queue to drain"); 11451553Srgrimes if (i == 10) 11461553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 114731492Swollman pp->printer, pp->remote_host); 11481553Srgrimes sleep(5 * 60); 11491553Srgrimes } 11501553Srgrimes if (i) 115131492Swollman pstatus(pp, "sending to %s", pp->remote_host); 115268253Sgad if (type == '\3') 115368253Sgad trstat_init(pp, file, job_dfcnt); 11541553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 11551553Srgrimes amt = BUFSIZ; 11561553Srgrimes if (i + amt > stb.st_size) 11571553Srgrimes amt = stb.st_size - i; 11581553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 11591553Srgrimes sizerr = 1; 11601553Srgrimes if (write(pfd, buf, amt) != amt) { 11611553Srgrimes (void) close(f); 116224831Sbrian if (tfd != -1 && type == '\3') { 116324831Sbrian tfd = -1; 116424831Sbrian unlink(tfile); 116524831Sbrian if (closedpr) 116631492Swollman openpr(pp); 116724831Sbrian } 11681553Srgrimes return(REPRINT); 11691553Srgrimes } 11701553Srgrimes } 11711553Srgrimes 11721553Srgrimes (void) close(f); 117324831Sbrian if (tfd != -1 && type == '\3') { 117424831Sbrian tfd = -1; 117524831Sbrian unlink(tfile); 117624831Sbrian } 11771553Srgrimes if (sizerr) { 117831492Swollman syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 11791553Srgrimes /* tell recvjob to ignore this file */ 11801553Srgrimes (void) write(pfd, "\1", 1); 118124831Sbrian if (closedpr) 118231492Swollman openpr(pp); 11831553Srgrimes return(ERROR); 11841553Srgrimes } 118531492Swollman if (write(pfd, "", 1) != 1 || response(pp)) { 118624831Sbrian if (closedpr) 118731492Swollman openpr(pp); 11881553Srgrimes return(REPRINT); 118924831Sbrian } 119024831Sbrian if (closedpr) 119131492Swollman openpr(pp); 119268253Sgad if (type == '\3') 119368253Sgad trstat_write(pp, TR_SENDING, stb.st_size, logname, 119478300Sgad pp->remote_host, origin_host); 11951553Srgrimes return(OK); 11961553Srgrimes} 11971553Srgrimes 11981553Srgrimes/* 11991553Srgrimes * Check to make sure there have been no errors and that both programs 12001553Srgrimes * are in sync with eachother. 12011553Srgrimes * Return non-zero if the connection was lost. 12021553Srgrimes */ 12031553Srgrimesstatic char 120478146Sgadresponse(const struct printer *pp) 12051553Srgrimes{ 12061553Srgrimes char resp; 12071553Srgrimes 12081553Srgrimes if (read(pfd, &resp, 1) != 1) { 120931492Swollman syslog(LOG_INFO, "%s: lost connection", pp->printer); 12101553Srgrimes return(-1); 12111553Srgrimes } 12121553Srgrimes return(resp); 12131553Srgrimes} 12141553Srgrimes 12151553Srgrimes/* 12161553Srgrimes * Banner printing stuff 12171553Srgrimes */ 12181553Srgrimesstatic void 121978146Sgadbanner(struct printer *pp, char *name1, char *name2) 12201553Srgrimes{ 12211553Srgrimes time_t tvec; 12221553Srgrimes 12231553Srgrimes time(&tvec); 122431492Swollman if (!pp->no_formfeed && !pp->tof) 122531492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 122631492Swollman if (pp->short_banner) { /* short banner only */ 12271553Srgrimes if (class[0]) { 12281553Srgrimes (void) write(ofd, class, strlen(class)); 12291553Srgrimes (void) write(ofd, ":", 1); 12301553Srgrimes } 12311553Srgrimes (void) write(ofd, name1, strlen(name1)); 12321553Srgrimes (void) write(ofd, " Job: ", 7); 12331553Srgrimes (void) write(ofd, name2, strlen(name2)); 12341553Srgrimes (void) write(ofd, " Date: ", 8); 12351553Srgrimes (void) write(ofd, ctime(&tvec), 24); 12361553Srgrimes (void) write(ofd, "\n", 1); 12371553Srgrimes } else { /* normal banner */ 12381553Srgrimes (void) write(ofd, "\n\n\n", 3); 123931492Swollman scan_out(pp, ofd, name1, '\0'); 12401553Srgrimes (void) write(ofd, "\n\n", 2); 124131492Swollman scan_out(pp, ofd, name2, '\0'); 12421553Srgrimes if (class[0]) { 12431553Srgrimes (void) write(ofd,"\n\n\n",3); 124431492Swollman scan_out(pp, ofd, class, '\0'); 12451553Srgrimes } 12461553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 12471553Srgrimes (void) write(ofd, name2, strlen(name2)); 12481553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 12491553Srgrimes (void) write(ofd, ctime(&tvec), 24); 12501553Srgrimes (void) write(ofd, "\n", 1); 12511553Srgrimes } 125231492Swollman if (!pp->no_formfeed) 125331492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 125431492Swollman pp->tof = 1; 12551553Srgrimes} 12561553Srgrimes 12571553Srgrimesstatic char * 125878146Sgadscnline(int key, char *p, int c) 12591553Srgrimes{ 126039084Swollman register int scnwidth; 12611553Srgrimes 12621553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 12631553Srgrimes key <<= 1; 12641553Srgrimes *p++ = key & 0200 ? c : BACKGND; 12651553Srgrimes } 12661553Srgrimes return (p); 12671553Srgrimes} 12681553Srgrimes 12691553Srgrimes#define TRC(q) (((q)-' ')&0177) 12701553Srgrimes 12711553Srgrimesstatic void 127278146Sgadscan_out(struct printer *pp, int scfd, char *scsp, int dlm) 12731553Srgrimes{ 12741553Srgrimes register char *strp; 127539084Swollman register int nchrs, j; 12761553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 12771553Srgrimes int d, scnhgt; 12781553Srgrimes 12791553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 12801553Srgrimes strp = &outbuf[0]; 12811553Srgrimes sp = scsp; 12821553Srgrimes for (nchrs = 0; ; ) { 12831553Srgrimes d = dropit(c = TRC(cc = *sp++)); 12841553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 12851553Srgrimes for (j = WIDTH; --j;) 12861553Srgrimes *strp++ = BACKGND; 12871553Srgrimes else 128831492Swollman strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 128931492Swollman if (*sp == dlm || *sp == '\0' || 129031492Swollman nchrs++ >= pp->page_width/(WIDTH+1)-1) 12911553Srgrimes break; 12921553Srgrimes *strp++ = BACKGND; 12931553Srgrimes *strp++ = BACKGND; 12941553Srgrimes } 12951553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 12961553Srgrimes ; 12971553Srgrimes strp++; 12988857Srgrimes *strp++ = '\n'; 12991553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 13001553Srgrimes } 13011553Srgrimes} 13021553Srgrimes 13031553Srgrimesstatic int 130478146Sgaddropit(int c) 13051553Srgrimes{ 13061553Srgrimes switch(c) { 13071553Srgrimes 13081553Srgrimes case TRC('_'): 13091553Srgrimes case TRC(';'): 13101553Srgrimes case TRC(','): 13111553Srgrimes case TRC('g'): 13121553Srgrimes case TRC('j'): 13131553Srgrimes case TRC('p'): 13141553Srgrimes case TRC('q'): 13151553Srgrimes case TRC('y'): 13161553Srgrimes return (DROP); 13171553Srgrimes 13181553Srgrimes default: 13191553Srgrimes return (0); 13201553Srgrimes } 13211553Srgrimes} 13221553Srgrimes 13231553Srgrimes/* 13241553Srgrimes * sendmail --- 13251553Srgrimes * tell people about job completion 13261553Srgrimes */ 13271553Srgrimesstatic void 132878146Sgadsendmail(struct printer *pp, char *user, int bombed) 13291553Srgrimes{ 13301553Srgrimes register int i; 13311553Srgrimes int p[2], s; 133278146Sgad register const 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; 134579452Sbrian execl(_PATH_SENDMAIL, cp, "-t", (char *)0); 134631492Swollman _exit(0); 13471553Srgrimes } else if (s > 0) { /* parent */ 13481553Srgrimes dup2(p[1], 1); 134978300Sgad printf("To: %s@%s\n", user, origin_host); 135031492Swollman printf("Subject: %s printer job \"%s\"\n", pp->printer, 135115648Sjoerg *jobname ? jobname : "<unknown>"); 135278300Sgad printf("Reply-To: root@%s\n\n", local_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: 136978300Sgad printf("\ncould not be printed without an account on %s\n", 137078300Sgad local_host); 137115648Sjoerg cp = "NOACCT"; 13721553Srgrimes break; 13731553Srgrimes case FILTERERR: 137468664Sgad if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 137568664Sgad || (fp = fopen(tempstderr, "r")) == NULL) { 137615648Sjoerg printf("\nhad some errors and may not have printed\n"); 13771553Srgrimes break; 13781553Srgrimes } 137915648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 13801553Srgrimes while ((i = getc(fp)) != EOF) 13811553Srgrimes putchar(i); 13821553Srgrimes (void) fclose(fp); 138315648Sjoerg cp = "FILTERERR"; 13841553Srgrimes break; 13851553Srgrimes case ACCESS: 13861553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 138715648Sjoerg cp = "ACCESS"; 13881553Srgrimes } 13891553Srgrimes fflush(stdout); 13901553Srgrimes (void) close(1); 139131492Swollman } else { 139231492Swollman syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 139331492Swollman return; 13941553Srgrimes } 13951553Srgrimes (void) close(p[0]); 13961553Srgrimes (void) close(p[1]); 139715648Sjoerg wait(NULL); 139815648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 139931492Swollman user, *jobname ? jobname : "<unknown>", pp->printer, cp); 14001553Srgrimes} 14011553Srgrimes 14021553Srgrimes/* 14031553Srgrimes * dofork - fork with retries on failure 14041553Srgrimes */ 14051553Srgrimesstatic int 140678146Sgaddofork(const struct printer *pp, int action) 14071553Srgrimes{ 140880230Sgad int i, fail, forkpid; 140960871Smpp struct passwd *pwd; 14101553Srgrimes 141180230Sgad forkpid = -1; 141280230Sgad if (daemon_uname == NULL) { 141380230Sgad pwd = getpwuid(pp->daemon_user); 141480230Sgad if (pwd == NULL) { 141580230Sgad syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file", 141680230Sgad pp->printer, pp->daemon_user); 141780230Sgad goto error_ret; 141880230Sgad } 141980230Sgad daemon_uname = strdup(pwd->pw_name); 142080230Sgad daemon_defgid = pwd->pw_gid; 142180230Sgad } 142280230Sgad 14231553Srgrimes for (i = 0; i < 20; i++) { 142480230Sgad forkpid = fork(); 142580230Sgad if (forkpid < 0) { 14261553Srgrimes sleep((unsigned)(i*i)); 14271553Srgrimes continue; 14281553Srgrimes } 14291553Srgrimes /* 14301553Srgrimes * Child should run as daemon instead of root 14311553Srgrimes */ 143278146Sgad if (forkpid == 0) { 143380230Sgad errno = 0; 143480230Sgad fail = initgroups(daemon_uname, daemon_defgid); 143580230Sgad if (fail) { 143680230Sgad syslog(LOG_ERR, "%s: initgroups(%s,%u): %m", 143780230Sgad pp->printer, daemon_uname, daemon_defgid); 143860871Smpp break; 143960871Smpp } 144080230Sgad fail = setgid(daemon_defgid); 144180230Sgad if (fail) { 144280230Sgad syslog(LOG_ERR, "%s: setgid(%u): %m", 144380230Sgad pp->printer, daemon_defgid); 144480230Sgad break; 144580230Sgad } 144680230Sgad fail = setuid(pp->daemon_user); 144780230Sgad if (fail) { 144880230Sgad syslog(LOG_ERR, "%s: setuid(%ld): %m", 144980230Sgad pp->printer, pp->daemon_user); 145080230Sgad break; 145180230Sgad } 145260871Smpp } 145380230Sgad return forkpid; 14541553Srgrimes } 14551553Srgrimes 145680230Sgad /* 145780230Sgad * An error occurred. If the error is in the child process, then 145880230Sgad * this routine MUST always exit(). DORETURN only effects how 145980230Sgad * errors should be handled in the parent process. 146080230Sgad */ 146180230Sgaderror_ret: 146280230Sgad if (forkpid == 0) { 146380230Sgad syslog(LOG_ERR, "%s: dofork(): aborting child process...", 146480230Sgad pp->printer); 146580230Sgad exit(1); 146680230Sgad } 146780230Sgad syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer); 146880230Sgad 146980230Sgad sleep(1); /* throttle errors, as a safety measure */ 14701553Srgrimes switch (action) { 14711553Srgrimes case DORETURN: 147280230Sgad return -1; 14731553Srgrimes default: 14741553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 147580230Sgad /* FALLTHROUGH */ 14761553Srgrimes case DOABORT: 14771553Srgrimes exit(1); 14781553Srgrimes } 14791553Srgrimes /*NOTREACHED*/ 14801553Srgrimes} 14811553Srgrimes 14821553Srgrimes/* 14831553Srgrimes * Kill child processes to abort current job. 14841553Srgrimes */ 14851553Srgrimesstatic void 148678146Sgadabortpr(int signo __unused) 14871553Srgrimes{ 148868664Sgad 148968664Sgad (void) unlink(tempstderr); 14901553Srgrimes kill(0, SIGINT); 14911553Srgrimes if (ofilter > 0) 14921553Srgrimes kill(ofilter, SIGCONT); 14931553Srgrimes while (wait(NULL) > 0) 14941553Srgrimes ; 149524831Sbrian if (ofilter > 0 && tfd != -1) 149624831Sbrian unlink(tfile); 14971553Srgrimes exit(0); 14981553Srgrimes} 14991553Srgrimes 15001553Srgrimesstatic void 150178146Sgadinit(struct printer *pp) 15021553Srgrimes{ 15031553Srgrimes char *s; 15041553Srgrimes 150531492Swollman sprintf(&width[2], "%ld", pp->page_width); 150631492Swollman sprintf(&length[2], "%ld", pp->page_length); 150731492Swollman sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 150831492Swollman sprintf(&pxlength[2], "%ld", pp->page_plength); 150931492Swollman if ((s = checkremote(pp)) != 0) { 151031492Swollman syslog(LOG_WARNING, "%s", s); 151131492Swollman free(s); 151231492Swollman } 151331492Swollman} 151431492Swollman 151531492Swollmanvoid 151678146Sgadstartprinting(const char *printer) 151731492Swollman{ 151831492Swollman struct printer myprinter, *pp = &myprinter; 151931492Swollman int status; 152031492Swollman 152131492Swollman init_printer(pp); 152231492Swollman status = getprintcap(printer, pp); 152331492Swollman switch(status) { 152431492Swollman case PCAPERR_OSERR: 152531492Swollman syslog(LOG_ERR, "can't open printer description file: %m"); 15261553Srgrimes exit(1); 152731492Swollman case PCAPERR_NOTFOUND: 15281553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 15291553Srgrimes exit(1); 153031492Swollman case PCAPERR_TCLOOP: 153131492Swollman fatal(pp, "potential reference loop detected in printcap file"); 153231492Swollman default: 153331492Swollman break; 153431492Swollman } 153531492Swollman printjob(pp); 15361553Srgrimes} 15371553Srgrimes 15381553Srgrimes/* 15391553Srgrimes * Acquire line printer or remote connection. 15401553Srgrimes */ 15411553Srgrimesstatic void 154278146Sgadopenpr(const struct printer *pp) 15431553Srgrimes{ 154431492Swollman int p[2]; 154515648Sjoerg char *cp; 15461553Srgrimes 154731492Swollman if (pp->remote) { 154831492Swollman openrem(pp); 154931492Swollman } else if (*pp->lp) { 155031492Swollman if ((cp = strchr(pp->lp, '@')) != NULL) 155131492Swollman opennet(pp); 155215648Sjoerg else 155331492Swollman opentty(pp); 15541553Srgrimes } else { 15551553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 155631492Swollman pp->printer); 15571553Srgrimes exit(1); 15581553Srgrimes } 155915648Sjoerg 15601553Srgrimes /* 15611553Srgrimes * Start up an output filter, if needed. 15621553Srgrimes */ 156331492Swollman if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 15641553Srgrimes pipe(p); 156531492Swollman if (pp->remote) { 156631492Swollman strcpy(tfile, TFILENAME); 156724831Sbrian tfd = mkstemp(tfile); 156824831Sbrian } 156931492Swollman if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 15701553Srgrimes dup2(p[0], 0); /* pipe is std in */ 157124831Sbrian /* tfile/printer is stdout */ 157231492Swollman dup2(pp->remote ? tfd : pfd, 1); 15738094Sjkh closelog(); 157431492Swollman closeallfds(3); 157531492Swollman if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 157631492Swollman cp = pp->filters[LPF_OUTPUT]; 15771553Srgrimes else 15781553Srgrimes cp++; 157979452Sbrian execl(pp->filters[LPF_OUTPUT], cp, width, length, 158079452Sbrian (char *)0); 158131492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 158231492Swollman pp->filters[LPF_OUTPUT]); 15831553Srgrimes exit(1); 15841553Srgrimes } 15851553Srgrimes (void) close(p[0]); /* close input side */ 15861553Srgrimes ofd = p[1]; /* use pipe for output */ 15871553Srgrimes } else { 15881553Srgrimes ofd = pfd; 15891553Srgrimes ofilter = 0; 15901553Srgrimes } 15911553Srgrimes} 15921553Srgrimes 159315648Sjoerg/* 159415648Sjoerg * Printer connected directly to the network 159515648Sjoerg * or to a terminal server on the net 159615648Sjoerg */ 159715648Sjoergstatic void 159878146Sgadopennet(const struct printer *pp) 159915648Sjoerg{ 160015648Sjoerg register int i; 160131492Swollman int resp; 160231492Swollman u_long port; 160331492Swollman char *ep; 160430407Sjoerg void (*savealrm)(int); 160515648Sjoerg 160631492Swollman port = strtoul(pp->lp, &ep, 0); 160738470Sbrian if (*ep != '@' || port > 65535) { 160831492Swollman syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 160931492Swollman pp->lp); 161015648Sjoerg exit(1); 161115648Sjoerg } 161231492Swollman ep++; 161315648Sjoerg 161415648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 161515648Sjoerg resp = -1; 161630407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 161731492Swollman alarm(pp->conn_timeout); 161831492Swollman pfd = getport(pp, ep, port); 161931020Sjoerg alarm(0); 162030407Sjoerg (void)signal(SIGALRM, savealrm); 162115648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 162215648Sjoerg resp = 1; 162315648Sjoerg else if (pfd >= 0) { 162415648Sjoerg /* 162515648Sjoerg * need to delay a bit for rs232 lines 162615648Sjoerg * to stabilize in case printer is 162715648Sjoerg * connected via a terminal server 162815648Sjoerg */ 162915648Sjoerg delay(500); 163015648Sjoerg break; 163115648Sjoerg } 163215648Sjoerg if (i == 1) { 163331492Swollman if (resp < 0) 163431492Swollman pstatus(pp, "waiting for %s to come up", 163531492Swollman pp->lp); 163631492Swollman else 163731492Swollman pstatus(pp, 163831492Swollman "waiting for access to printer on %s", 163931492Swollman pp->lp); 164015648Sjoerg } 164115648Sjoerg sleep(i); 164215648Sjoerg } 164379739Sgad pstatus(pp, "sending to %s port %lu", ep, port); 164415648Sjoerg} 164515648Sjoerg 164615648Sjoerg/* 164715648Sjoerg * Printer is connected to an RS232 port on this host 164815648Sjoerg */ 164915648Sjoergstatic void 165078146Sgadopentty(const struct printer *pp) 165115648Sjoerg{ 165215648Sjoerg register int i; 165315648Sjoerg 165415648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 165531492Swollman pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 165615648Sjoerg if (pfd >= 0) { 165715648Sjoerg delay(500); 165815648Sjoerg break; 165915648Sjoerg } 166015648Sjoerg if (errno == ENOENT) { 166131492Swollman syslog(LOG_ERR, "%s: %m", pp->lp); 166215648Sjoerg exit(1); 166315648Sjoerg } 166415648Sjoerg if (i == 1) 166531492Swollman pstatus(pp, 166631492Swollman "waiting for %s to become ready (offline?)", 166731492Swollman pp->printer); 166815648Sjoerg sleep(i); 166915648Sjoerg } 167015648Sjoerg if (isatty(pfd)) 167131492Swollman setty(pp); 167231492Swollman pstatus(pp, "%s is ready and printing", pp->printer); 167315648Sjoerg} 167415648Sjoerg 167515648Sjoerg/* 167615648Sjoerg * Printer is on a remote host 167715648Sjoerg */ 167815648Sjoergstatic void 167978146Sgadopenrem(const struct printer *pp) 168015648Sjoerg{ 168131492Swollman register int i; 168227748Simp int resp; 168330407Sjoerg void (*savealrm)(int); 168415648Sjoerg 168515648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 168615648Sjoerg resp = -1; 168730407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 168831492Swollman alarm(pp->conn_timeout); 168931492Swollman pfd = getport(pp, pp->remote_host, 0); 169031020Sjoerg alarm(0); 169130407Sjoerg (void)signal(SIGALRM, savealrm); 169215648Sjoerg if (pfd >= 0) { 169331492Swollman if ((writel(pfd, "\2", pp->remote_queue, "\n", 169431492Swollman (char *)0) 169531492Swollman == 2 + strlen(pp->remote_queue)) 169631492Swollman && (resp = response(pp)) == 0) 169715648Sjoerg break; 169815648Sjoerg (void) close(pfd); 169915648Sjoerg } 170015648Sjoerg if (i == 1) { 170115648Sjoerg if (resp < 0) 170231492Swollman pstatus(pp, "waiting for %s to come up", 170331492Swollman pp->remote_host); 170415648Sjoerg else { 170531492Swollman pstatus(pp, 170631492Swollman "waiting for queue to be enabled on %s", 170731492Swollman pp->remote_host); 170815648Sjoerg i = 256; 170915648Sjoerg } 171015648Sjoerg } 171115648Sjoerg sleep(i); 171215648Sjoerg } 171331492Swollman pstatus(pp, "sending to %s", pp->remote_host); 171415648Sjoerg} 171515648Sjoerg 17161553Srgrimes/* 17171553Srgrimes * setup tty lines. 17181553Srgrimes */ 17191553Srgrimesstatic void 172078146Sgadsetty(const struct printer *pp) 17211553Srgrimes{ 172215032Ssef struct termios ttybuf; 17231553Srgrimes 17241553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 172531492Swollman syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 17261553Srgrimes exit(1); 17271553Srgrimes } 172815032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 172931492Swollman syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 17301553Srgrimes exit(1); 17311553Srgrimes } 173231492Swollman if (pp->baud_rate > 0) 173331492Swollman cfsetspeed(&ttybuf, pp->baud_rate); 173431492Swollman if (pp->mode_set) { 173531492Swollman char *s = strdup(pp->mode_set), *tmp; 173615032Ssef 173731492Swollman while ((tmp = strsep(&s, ",")) != NULL) { 173839084Swollman (void) msearch(tmp, &ttybuf); 17391553Srgrimes } 17401553Srgrimes } 174131492Swollman if (pp->mode_set != 0 || pp->baud_rate > 0) { 174215032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 174331492Swollman syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 17441553Srgrimes } 17451553Srgrimes } 17461553Srgrimes} 17471553Srgrimes 174827757Simp#ifdef __STDC__ 17491553Srgrimes#include <stdarg.h> 17501553Srgrimes#else 17511553Srgrimes#include <varargs.h> 17521553Srgrimes#endif 17531553Srgrimes 175415648Sjoergstatic void 175527757Simp#ifdef __STDC__ 175631492Swollmanpstatus(const struct printer *pp, const char *msg, ...) 17571553Srgrimes#else 175831492Swollmanpstatus(pp, msg, va_alist) 175931492Swollman const struct printer *pp; 17601553Srgrimes char *msg; 17611553Srgrimes va_dcl 17621553Srgrimes#endif 17631553Srgrimes{ 176431492Swollman int fd; 176531492Swollman char *buf; 17661553Srgrimes va_list ap; 176727757Simp#ifdef __STDC__ 17681553Srgrimes va_start(ap, msg); 17691553Srgrimes#else 17701553Srgrimes va_start(ap); 17711553Srgrimes#endif 17721553Srgrimes 17731553Srgrimes umask(0); 177431492Swollman fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 177531492Swollman if (fd < 0) { 177631492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 17771553Srgrimes exit(1); 17781553Srgrimes } 17791553Srgrimes ftruncate(fd, 0); 178031492Swollman vasprintf(&buf, msg, ap); 17811553Srgrimes va_end(ap); 178231492Swollman writel(fd, buf, "\n", (char *)0); 178331492Swollman close(fd); 178431492Swollman free(buf); 17851553Srgrimes} 178630407Sjoerg 178730407Sjoergvoid 178878146Sgadalarmhandler(int signo __unused) 178930407Sjoerg{ 179078146Sgad /* the signal is ignored */ 179178146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 179230407Sjoerg} 1793