printjob.c revision 53956
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 53956 1999-11-30 16:15:22Z ache $"; 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 */ 981553Srgrimesstatic int lfd; /* lock file descriptor */ 991553Srgrimesstatic int ofd; /* output filter file descriptor */ 1001553Srgrimesstatic int ofilter; /* id of output filter, if any */ 10124831Sbrianstatic int tfd = -1; /* output filter temp file output */ 1021553Srgrimesstatic int pfd; /* prstatic inter file descriptor */ 1031553Srgrimesstatic int pid; /* pid of lpd process */ 1041553Srgrimesstatic int prchild; /* id of pr process */ 1051553Srgrimesstatic char title[80]; /* ``pr'' title */ 10653956Sachestatic char locale[80]; /* ``pr'' locale */ 1071553Srgrimes 1081553Srgrimesstatic char class[32]; /* classification field */ 1091553Srgrimesstatic char fromhost[32]; /* user's host machine */ 1101553Srgrimes /* indentation size in static characters */ 1118857Srgrimesstatic char indent[10] = "-i0"; 1121553Srgrimesstatic char jobname[100]; /* job or file name */ 1131553Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1141553Srgrimesstatic char logname[32]; /* user's login name */ 1151553Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1161553Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 11724831Sbrianstatic char tempfile[] = "errsXXXXXX"; /* file name for filter errors */ 1181553Srgrimesstatic char width[10] = "-w"; /* page width in static characters */ 11924831Sbrian#define TFILENAME "fltXXXXXX" 12024831Sbrianstatic char tfile[] = TFILENAME; /* file name for filter output */ 1211553Srgrimes 1221553Srgrimesstatic void abortpr __P((int)); 12330407Sjoergstatic void alarmhandler __P((int)); 12431492Swollmanstatic void banner __P((struct printer *pp, char *name1, char *name2)); 12531492Swollmanstatic int dofork __P((const struct printer *pp, int action)); 1261553Srgrimesstatic int dropit __P((int)); 12731492Swollmanstatic void init __P((struct printer *pp)); 12831492Swollmanstatic void openpr __P((const struct printer *pp)); 12931492Swollmanstatic void opennet __P((const struct printer *pp)); 13031492Swollmanstatic void opentty __P((const struct printer *pp)); 13131492Swollmanstatic void openrem __P((const struct printer *pp)); 13231492Swollmanstatic int print __P((struct printer *pp, int format, char *file)); 13331492Swollmanstatic int printit __P((struct printer *pp, char *file)); 13431492Swollmanstatic void pstatus __P((const struct printer *, const char *, ...)); 13531492Swollmanstatic char response __P((const struct printer *pp)); 13631492Swollmanstatic void scan_out __P((struct printer *pp, int scfd, char *scsp, 13731492Swollman int dlm)); 1381553Srgrimesstatic char *scnline __P((int, char *, int)); 13931492Swollmanstatic int sendfile __P((struct printer *pp, int type, char *file, 14031492Swollman int format)); 14131492Swollmanstatic int sendit __P((struct printer *pp, char *file)); 14231492Swollmanstatic void sendmail __P((struct printer *pp, char *user, int bombed)); 14331492Swollmanstatic void setty __P((const struct printer *pp)); 1441553Srgrimes 1451553Srgrimesvoid 14631492Swollmanprintjob(pp) 14731492Swollman struct printer *pp; 1481553Srgrimes{ 1491553Srgrimes struct stat stb; 1501553Srgrimes register struct queue *q, **qp; 1511553Srgrimes struct queue **queue; 1521553Srgrimes register int i, nitems; 15315648Sjoerg off_t pidoff; 15415648Sjoerg int errcnt, count = 0; 1551553Srgrimes 15631492Swollman init(pp); /* set up capabilities */ 15731492Swollman (void) write(1, "", 1); /* ack that daemon is started */ 1581553Srgrimes (void) close(2); /* set up log file */ 15931492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 16031492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1611553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1621553Srgrimes } 1631553Srgrimes setgid(getegid()); 1641553Srgrimes pid = getpid(); /* for use with lprm */ 1651553Srgrimes setpgrp(0, pid); 1661553Srgrimes signal(SIGHUP, abortpr); 1671553Srgrimes signal(SIGINT, abortpr); 1681553Srgrimes signal(SIGQUIT, abortpr); 1691553Srgrimes signal(SIGTERM, abortpr); 1701553Srgrimes 1711553Srgrimes (void) mktemp(tempfile); 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 } 22031492Swollman openpr(pp); /* open printer or remote */ 2211553Srgrimesagain: 2221553Srgrimes /* 2231553Srgrimes * we found something to do now do it -- 2241553Srgrimes * write the name of the current control file into the lock file 2251553Srgrimes * so the spool queue program can tell what we're working on 2261553Srgrimes */ 2271553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2281553Srgrimes q = *qp++; 2291553Srgrimes if (stat(q->q_name, &stb) < 0) 2301553Srgrimes continue; 23115648Sjoerg errcnt = 0; 2321553Srgrimes restart: 23315648Sjoerg (void) lseek(lfd, pidoff, 0); 23427748Simp (void) snprintf(line, sizeof(line), "%s\n", q->q_name); 2351553Srgrimes i = strlen(line); 2361553Srgrimes if (write(lfd, line, i) != i) 23731492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 23831492Swollman pp->lock_file); 23931492Swollman if (!pp->remote) 24031492Swollman i = printit(pp, q->q_name); 2411553Srgrimes else 24231492Swollman i = sendit(pp, q->q_name); 2431553Srgrimes /* 2441553Srgrimes * Check to see if we are supposed to stop printing or 2451553Srgrimes * if we are to rebuild the queue. 2461553Srgrimes */ 2471553Srgrimes if (fstat(lfd, &stb) == 0) { 2481553Srgrimes /* stop printing before starting next job? */ 24931492Swollman if (stb.st_mode & LFM_PRINT_DIS) 2501553Srgrimes goto done; 2511553Srgrimes /* rebuild queue (after lpc topq) */ 25231492Swollman if (stb.st_mode & LFM_RESET_QUE) { 25331492Swollman for (free(q); nitems--; free(q)) 2541553Srgrimes q = *qp++; 25531492Swollman if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 25631492Swollman < 0) 2571553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 25831492Swollman pp->printer, pp->lock_file); 2591553Srgrimes break; 2601553Srgrimes } 2611553Srgrimes } 2621553Srgrimes if (i == OK) /* file ok and printed */ 2631553Srgrimes count++; 26415648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 26515648Sjoerg /* try reprinting the job */ 26631492Swollman syslog(LOG_INFO, "restarting %s", pp->printer); 2671553Srgrimes if (ofilter > 0) { 2681553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2691553Srgrimes (void) close(ofd); 27015648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2711553Srgrimes ; 2721553Srgrimes ofilter = 0; 2731553Srgrimes } 2741553Srgrimes (void) close(pfd); /* close printer */ 2751553Srgrimes if (ftruncate(lfd, pidoff) < 0) 27631492Swollman syslog(LOG_WARNING, "%s: %s: %m", 27731492Swollman pp->printer, pp->lock_file); 27831492Swollman openpr(pp); /* try to reopen printer */ 2791553Srgrimes goto restart; 28015648Sjoerg } else { 28131492Swollman syslog(LOG_WARNING, "%s: job could not be %s (%s)", 28231492Swollman pp->printer, 28331492Swollman pp->remote ? "sent to remote host" : "printed", 28431492Swollman q->q_name); 28515648Sjoerg if (i == REPRINT) { 28627748Simp /* ensure we don't attempt this job again */ 28715648Sjoerg (void) unlink(q->q_name); 28815648Sjoerg q->q_name[0] = 'd'; 28915648Sjoerg (void) unlink(q->q_name); 29015648Sjoerg if (logname[0]) 29131492Swollman sendmail(pp, logname, FATALERR); 29215648Sjoerg } 2931553Srgrimes } 2941553Srgrimes } 29531492Swollman free(queue); 2961553Srgrimes /* 2971553Srgrimes * search the spool directory for more work. 2981553Srgrimes */ 29931492Swollman if ((nitems = getq(pp, &queue)) < 0) { 30031492Swollman syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 30131492Swollman pp->spool_dir); 3021553Srgrimes exit(1); 3031553Srgrimes } 3041553Srgrimes if (nitems == 0) { /* no more work to do */ 3051553Srgrimes done: 3061553Srgrimes if (count > 0) { /* Files actually printed */ 30731492Swollman if (!pp->no_formfeed && !pp->tof) 30831492Swollman (void) write(ofd, pp->form_feed, 30931492Swollman strlen(pp->form_feed)); 31031492Swollman if (pp->trailer != NULL) /* output trailer */ 31131492Swollman (void) write(ofd, pp->trailer, 31231492Swollman strlen(pp->trailer)); 3131553Srgrimes } 31419202Simp (void) close(ofd); 31519202Simp (void) wait(NULL); 3161553Srgrimes (void) unlink(tempfile); 3171553Srgrimes exit(0); 3181553Srgrimes } 3191553Srgrimes goto again; 3201553Srgrimes} 3211553Srgrimes 3221553Srgrimeschar fonts[4][50]; /* fonts for troff */ 3231553Srgrimes 3241553Srgrimeschar ifonts[4][40] = { 3251553Srgrimes _PATH_VFONTR, 3261553Srgrimes _PATH_VFONTI, 3271553Srgrimes _PATH_VFONTB, 3281553Srgrimes _PATH_VFONTS, 3291553Srgrimes}; 3301553Srgrimes 3311553Srgrimes/* 3321553Srgrimes * The remaining part is the reading of the control file (cf) 3331553Srgrimes * and performing the various actions. 3341553Srgrimes */ 3351553Srgrimesstatic int 33631492Swollmanprintit(pp, file) 33731492Swollman struct printer *pp; 3381553Srgrimes char *file; 3391553Srgrimes{ 3401553Srgrimes register int i; 3411553Srgrimes char *cp; 3421553Srgrimes int bombed = OK; 3431553Srgrimes 3441553Srgrimes /* 3451553Srgrimes * open control file; ignore if no longer there. 3461553Srgrimes */ 3471553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 34831492Swollman syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 3491553Srgrimes return(OK); 3501553Srgrimes } 3511553Srgrimes /* 3521553Srgrimes * Reset troff fonts. 3531553Srgrimes */ 3541553Srgrimes for (i = 0; i < 4; i++) 3551553Srgrimes strcpy(fonts[i], ifonts[i]); 35631492Swollman sprintf(&width[2], "%ld", pp->page_width); 3571553Srgrimes strcpy(indent+2, "0"); 3581553Srgrimes 3591553Srgrimes /* 3601553Srgrimes * read the control file for work to do 3611553Srgrimes * 3621553Srgrimes * file format -- first character in the line is a command 3631553Srgrimes * rest of the line is the argument. 3641553Srgrimes * valid commands are: 3651553Srgrimes * 3661553Srgrimes * S -- "stat info" for symbolic link protection 3671553Srgrimes * J -- "job name" on banner page 3681553Srgrimes * C -- "class name" on banner page 3691553Srgrimes * L -- "literal" user's name to print on banner 3701553Srgrimes * T -- "title" for pr 3711553Srgrimes * H -- "host name" of machine where lpr was done 3721553Srgrimes * P -- "person" user's login name 3731553Srgrimes * I -- "indent" amount to indent output 37415648Sjoerg * R -- laser dpi "resolution" 3751553Srgrimes * f -- "file name" name of text file to print 3761553Srgrimes * l -- "file name" text file with control chars 3771553Srgrimes * p -- "file name" text file to print with pr(1) 3781553Srgrimes * t -- "file name" troff(1) file to print 3791553Srgrimes * n -- "file name" ditroff(1) file to print 3801553Srgrimes * d -- "file name" dvi file to print 3811553Srgrimes * g -- "file name" plot(1G) file to print 3821553Srgrimes * v -- "file name" plain raster file to print 3831553Srgrimes * c -- "file name" cifplot file to print 3841553Srgrimes * 1 -- "R font file" for troff 3851553Srgrimes * 2 -- "I font file" for troff 3861553Srgrimes * 3 -- "B font file" for troff 3871553Srgrimes * 4 -- "S font file" for troff 3881553Srgrimes * N -- "name" of file (used by lpq) 3891553Srgrimes * U -- "unlink" name of file to remove 3901553Srgrimes * (after we print it. (Pass 2 only)). 3911553Srgrimes * M -- "mail" to user when done printing 39253956Sache * Z -- "locale" for pr 3931553Srgrimes * 3941553Srgrimes * getline reads a line and expands tabs to blanks 3951553Srgrimes */ 3961553Srgrimes 3971553Srgrimes /* pass 1 */ 3981553Srgrimes 3991553Srgrimes while (getline(cfp)) 4001553Srgrimes switch (line[0]) { 4011553Srgrimes case 'H': 40227748Simp strncpy(fromhost, line+1, sizeof(fromhost) - 1); 40327748Simp fromhost[sizeof(fromhost) - 1] = '\0'; 40427748Simp if (class[0] == '\0') { 40527748Simp strncpy(class, line+1, sizeof(class) - 1); 40627748Simp class[sizeof(class) - 1] = '\0'; 40727748Simp } 4081553Srgrimes continue; 4091553Srgrimes 4101553Srgrimes case 'P': 41127748Simp strncpy(logname, line+1, sizeof(logname) - 1); 41227748Simp logname[sizeof(logname) - 1] = '\0'; 41331492Swollman if (pp->restricted) { /* restricted */ 4141553Srgrimes if (getpwnam(logname) == NULL) { 4151553Srgrimes bombed = NOACCT; 41631492Swollman sendmail(pp, line+1, bombed); 4171553Srgrimes goto pass2; 4181553Srgrimes } 4191553Srgrimes } 4201553Srgrimes continue; 4211553Srgrimes 4221553Srgrimes case 'S': 4231553Srgrimes cp = line+1; 4241553Srgrimes i = 0; 4251553Srgrimes while (*cp >= '0' && *cp <= '9') 4261553Srgrimes i = i * 10 + (*cp++ - '0'); 4271553Srgrimes fdev = i; 4281553Srgrimes cp++; 4291553Srgrimes i = 0; 4301553Srgrimes while (*cp >= '0' && *cp <= '9') 4311553Srgrimes i = i * 10 + (*cp++ - '0'); 4321553Srgrimes fino = i; 4331553Srgrimes continue; 4341553Srgrimes 4351553Srgrimes case 'J': 43627748Simp if (line[1] != '\0') { 43727748Simp strncpy(jobname, line+1, sizeof(jobname) - 1); 43827748Simp jobname[sizeof(jobname) - 1] = '\0'; 43927748Simp } else 4401553Srgrimes strcpy(jobname, " "); 4411553Srgrimes continue; 4421553Srgrimes 4431553Srgrimes case 'C': 4441553Srgrimes if (line[1] != '\0') 44527748Simp strncpy(class, line+1, sizeof(class) - 1); 4461553Srgrimes else if (class[0] == '\0') 4471553Srgrimes gethostname(class, sizeof(class)); 44827748Simp class[sizeof(class) - 1] = '\0'; 4491553Srgrimes continue; 4501553Srgrimes 4511553Srgrimes case 'T': /* header title for pr */ 45227748Simp strncpy(title, line+1, sizeof(title) - 1); 45327748Simp title[sizeof(title) - 1] = '\0'; 4541553Srgrimes continue; 4551553Srgrimes 4561553Srgrimes case 'L': /* identification line */ 45731492Swollman if (!pp->no_header && !pp->header_last) 45831492Swollman banner(pp, line+1, jobname); 4591553Srgrimes continue; 4601553Srgrimes 4611553Srgrimes case '1': /* troff fonts */ 4621553Srgrimes case '2': 4631553Srgrimes case '3': 4641553Srgrimes case '4': 46527748Simp if (line[1] != '\0') { 46627748Simp strncpy(fonts[line[0]-'1'], line+1, 46727748Simp 50-1); 46827748Simp fonts[line[0]-'1'][50-1] = '\0'; 46927748Simp } 4701553Srgrimes continue; 4711553Srgrimes 4721553Srgrimes case 'W': /* page width */ 47327748Simp strncpy(width+2, line+1, sizeof(width) - 3); 47427748Simp width[2+sizeof(width) - 3] = '\0'; 4751553Srgrimes continue; 4761553Srgrimes 4771553Srgrimes case 'I': /* indent amount */ 47827748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 47927748Simp indent[2+sizeof(indent) - 3] = '\0'; 4801553Srgrimes continue; 4811553Srgrimes 48253956Sache case 'Z': /* locale for pr */ 48353956Sache strncpy(locale, line+1, sizeof(locale) - 1); 48453956Sache locale[sizeof(locale) - 1] = '\0'; 48553956Sache continue; 48653956Sache 4871553Srgrimes default: /* some file to print */ 48831492Swollman switch (i = print(pp, line[0], line+1)) { 4891553Srgrimes case ERROR: 4901553Srgrimes if (bombed == OK) 4911553Srgrimes bombed = FATALERR; 4921553Srgrimes break; 4931553Srgrimes case REPRINT: 4941553Srgrimes (void) fclose(cfp); 4951553Srgrimes return(REPRINT); 4961553Srgrimes case FILTERERR: 4971553Srgrimes case ACCESS: 4981553Srgrimes bombed = i; 49931492Swollman sendmail(pp, logname, bombed); 5001553Srgrimes } 5011553Srgrimes title[0] = '\0'; 5021553Srgrimes continue; 5031553Srgrimes 5041553Srgrimes case 'N': 5051553Srgrimes case 'U': 5061553Srgrimes case 'M': 50715648Sjoerg case 'R': 5081553Srgrimes continue; 5091553Srgrimes } 5101553Srgrimes 5111553Srgrimes /* pass 2 */ 5121553Srgrimes 5131553Srgrimespass2: 5141553Srgrimes fseek(cfp, 0L, 0); 5151553Srgrimes while (getline(cfp)) 5161553Srgrimes switch (line[0]) { 5171553Srgrimes case 'L': /* identification line */ 51831492Swollman if (!pp->no_header && pp->header_last) 51931492Swollman banner(pp, line+1, jobname); 5201553Srgrimes continue; 5211553Srgrimes 5221553Srgrimes case 'M': 5231553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 52431492Swollman sendmail(pp, line+1, bombed); 5251553Srgrimes continue; 5261553Srgrimes 5271553Srgrimes case 'U': 52827748Simp if (strchr(line+1, '/')) 52927748Simp continue; 5301553Srgrimes (void) unlink(line+1); 5311553Srgrimes } 5321553Srgrimes /* 5331553Srgrimes * clean-up in case another control file exists 5341553Srgrimes */ 5351553Srgrimes (void) fclose(cfp); 5361553Srgrimes (void) unlink(file); 5371553Srgrimes return(bombed == OK ? OK : ERROR); 5381553Srgrimes} 5391553Srgrimes 5401553Srgrimes/* 5411553Srgrimes * Print a file. 5421553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 5431553Srgrimes * Return -1 if a non-recoverable error occured, 5441553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 5451553Srgrimes * 1 if we should try to reprint this job and 5461553Srgrimes * 0 if all is well. 5471553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5481553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5491553Srgrimes */ 5501553Srgrimesstatic int 55131492Swollmanprint(pp, format, file) 55231492Swollman struct printer *pp; 5531553Srgrimes int format; 5541553Srgrimes char *file; 5551553Srgrimes{ 55653956Sache register int n, i; 5571553Srgrimes register char *prog; 55831492Swollman int fi, fo; 5591553Srgrimes FILE *fp; 5601553Srgrimes char *av[15], buf[BUFSIZ]; 5611553Srgrimes int pid, p[2], stopped = 0; 5621553Srgrimes union wait status; 5631553Srgrimes struct stat stb; 5641553Srgrimes 5651553Srgrimes if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 5661553Srgrimes return(ERROR); 5671553Srgrimes /* 5681553Srgrimes * Check to see if data file is a symbolic link. If so, it should 5691553Srgrimes * still point to the same file or someone is trying to print 5701553Srgrimes * something he shouldn't. 5711553Srgrimes */ 5721553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 5731553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 5741553Srgrimes return(ACCESS); 57531492Swollman if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 57631492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 57731492Swollman pp->tof = 1; 5781553Srgrimes } 57931492Swollman if (pp->filters[LPF_INPUT] == NULL 58031492Swollman && (format == 'f' || format == 'l')) { 58131492Swollman pp->tof = 0; 5821553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 5831553Srgrimes if (write(ofd, buf, n) != n) { 5841553Srgrimes (void) close(fi); 5851553Srgrimes return(REPRINT); 5861553Srgrimes } 5871553Srgrimes (void) close(fi); 5881553Srgrimes return(OK); 5891553Srgrimes } 5901553Srgrimes switch (format) { 5911553Srgrimes case 'p': /* print file using 'pr' */ 59231492Swollman if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 5931553Srgrimes prog = _PATH_PR; 59453956Sache i = 0; 59553956Sache av[i++] = "pr"; 59653956Sache av[i++] = width; 59753956Sache av[i++] = length; 59853956Sache av[i++] = "-h"; 59953956Sache av[i++] = *title ? title : " "; 60053956Sache av[i++] = "-L"; 60153956Sache av[i++] = *locale ? locale : "C"; 60253956Sache av[i++] = "-F"; 60353956Sache av[i] = 0; 6041553Srgrimes fo = ofd; 6051553Srgrimes goto start; 6061553Srgrimes } 6071553Srgrimes pipe(p); 60831492Swollman if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 6091553Srgrimes dup2(fi, 0); /* file is stdin */ 6101553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 6118094Sjkh closelog(); 61231492Swollman closeallfds(3); 6131553Srgrimes execl(_PATH_PR, "pr", width, length, 61453956Sache "-h", *title ? title : " ", 61553956Sache "-L", *locale ? locale : "C", 61653956Sache "-F", 0); 6171553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 6181553Srgrimes exit(2); 6191553Srgrimes } 6201553Srgrimes (void) close(p[1]); /* close output side */ 6211553Srgrimes (void) close(fi); 6221553Srgrimes if (prchild < 0) { 6231553Srgrimes prchild = 0; 6241553Srgrimes (void) close(p[0]); 6251553Srgrimes return(ERROR); 6261553Srgrimes } 6271553Srgrimes fi = p[0]; /* use pipe for input */ 6281553Srgrimes case 'f': /* print plain text file */ 62931492Swollman prog = pp->filters[LPF_INPUT]; 6301553Srgrimes av[1] = width; 6311553Srgrimes av[2] = length; 6321553Srgrimes av[3] = indent; 6331553Srgrimes n = 4; 6341553Srgrimes break; 6351553Srgrimes case 'l': /* like 'f' but pass control characters */ 63631492Swollman prog = pp->filters[LPF_INPUT]; 6371553Srgrimes av[1] = "-c"; 6381553Srgrimes av[2] = width; 6391553Srgrimes av[3] = length; 6401553Srgrimes av[4] = indent; 6411553Srgrimes n = 5; 6421553Srgrimes break; 6431553Srgrimes case 'r': /* print a fortran text file */ 64431492Swollman prog = pp->filters[LPF_FORTRAN]; 6451553Srgrimes av[1] = width; 6461553Srgrimes av[2] = length; 6471553Srgrimes n = 3; 6481553Srgrimes break; 6491553Srgrimes case 't': /* print troff output */ 6501553Srgrimes case 'n': /* print ditroff output */ 6511553Srgrimes case 'd': /* print tex output */ 6521553Srgrimes (void) unlink(".railmag"); 6531553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 65431492Swollman syslog(LOG_ERR, "%s: cannot create .railmag", 65531492Swollman pp->printer); 6561553Srgrimes (void) unlink(".railmag"); 6571553Srgrimes } else { 6581553Srgrimes for (n = 0; n < 4; n++) { 6591553Srgrimes if (fonts[n][0] != '/') 6601553Srgrimes (void) write(fo, _PATH_VFONT, 6611553Srgrimes sizeof(_PATH_VFONT) - 1); 6621553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 6631553Srgrimes (void) write(fo, "\n", 1); 6641553Srgrimes } 6651553Srgrimes (void) close(fo); 6661553Srgrimes } 66731492Swollman prog = (format == 't') ? pp->filters[LPF_TROFF] 66831492Swollman : ((format == 'n') ? pp->filters[LPF_DITROFF] 66931492Swollman : pp->filters[LPF_DVI]); 6701553Srgrimes av[1] = pxwidth; 6711553Srgrimes av[2] = pxlength; 6721553Srgrimes n = 3; 6731553Srgrimes break; 6741553Srgrimes case 'c': /* print cifplot output */ 67531492Swollman prog = pp->filters[LPF_CIFPLOT]; 6761553Srgrimes av[1] = pxwidth; 6771553Srgrimes av[2] = pxlength; 6781553Srgrimes n = 3; 6791553Srgrimes break; 6801553Srgrimes case 'g': /* print plot(1G) output */ 68131492Swollman prog = pp->filters[LPF_GRAPH]; 6821553Srgrimes av[1] = pxwidth; 6831553Srgrimes av[2] = pxlength; 6841553Srgrimes n = 3; 6851553Srgrimes break; 6861553Srgrimes case 'v': /* print raster output */ 68731492Swollman prog = pp->filters[LPF_RASTER]; 6881553Srgrimes av[1] = pxwidth; 6891553Srgrimes av[2] = pxlength; 6901553Srgrimes n = 3; 6911553Srgrimes break; 6921553Srgrimes default: 6931553Srgrimes (void) close(fi); 6941553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 69531492Swollman pp->printer, format); 6961553Srgrimes return(ERROR); 6971553Srgrimes } 69815648Sjoerg if (prog == NULL) { 69915648Sjoerg (void) close(fi); 70015648Sjoerg syslog(LOG_ERR, 70115648Sjoerg "%s: no filter found in printcap for format character '%c'", 70231492Swollman pp->printer, format); 70315648Sjoerg return(ERROR); 70415648Sjoerg } 70527635Simp if ((av[0] = strrchr(prog, '/')) != NULL) 7061553Srgrimes av[0]++; 7071553Srgrimes else 7081553Srgrimes av[0] = prog; 7091553Srgrimes av[n++] = "-n"; 7101553Srgrimes av[n++] = logname; 7111553Srgrimes av[n++] = "-h"; 7121553Srgrimes av[n++] = fromhost; 71331492Swollman av[n++] = pp->acct_file; 7141553Srgrimes av[n] = 0; 7151553Srgrimes fo = pfd; 7161553Srgrimes if (ofilter > 0) { /* stop output filter */ 7171553Srgrimes write(ofd, "\031\1", 2); 7181553Srgrimes while ((pid = 7191553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 7201553Srgrimes ; 7211553Srgrimes if (status.w_stopval != WSTOPPED) { 7221553Srgrimes (void) close(fi); 72315648Sjoerg syslog(LOG_WARNING, 72431492Swollman "%s: output filter died " 72531492Swollman "(retcode=%d termsig=%d)", 72631492Swollman pp->printer, status.w_retcode, 72731492Swollman status.w_termsig); 7281553Srgrimes return(REPRINT); 7291553Srgrimes } 7301553Srgrimes stopped++; 7311553Srgrimes } 7321553Srgrimesstart: 73331492Swollman if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 7341553Srgrimes dup2(fi, 0); 7351553Srgrimes dup2(fo, 1); 7361553Srgrimes n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 7371553Srgrimes if (n >= 0) 7381553Srgrimes dup2(n, 2); 7398094Sjkh closelog(); 74031492Swollman closeallfds(3); 7411553Srgrimes execv(prog, av); 7421553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 7431553Srgrimes exit(2); 7441553Srgrimes } 7451553Srgrimes (void) close(fi); 7461553Srgrimes if (child < 0) 7471553Srgrimes status.w_retcode = 100; 7481553Srgrimes else 7491553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 7501553Srgrimes ; 7511553Srgrimes child = 0; 7521553Srgrimes prchild = 0; 7531553Srgrimes if (stopped) { /* restart output filter */ 7541553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 7551553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 7561553Srgrimes exit(1); 7571553Srgrimes } 7581553Srgrimes } 75931492Swollman pp->tof = 0; 7601553Srgrimes 7611553Srgrimes /* Copy filter output to "lf" logfile */ 76227748Simp if ((fp = fopen(tempfile, "r"))) { 7631553Srgrimes while (fgets(buf, sizeof(buf), fp)) 7641553Srgrimes fputs(buf, stderr); 7651553Srgrimes fclose(fp); 7661553Srgrimes } 7671553Srgrimes 7681553Srgrimes if (!WIFEXITED(status)) { 76915648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 77031492Swollman pp->printer, format, status.w_termsig); 7711553Srgrimes return(ERROR); 7721553Srgrimes } 7731553Srgrimes switch (status.w_retcode) { 7741553Srgrimes case 0: 77531492Swollman pp->tof = 1; 7761553Srgrimes return(OK); 7771553Srgrimes case 1: 7781553Srgrimes return(REPRINT); 77915648Sjoerg case 2: 78015648Sjoerg return(ERROR); 7811553Srgrimes default: 78215648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 78331492Swollman pp->printer, format, status.w_retcode); 78415648Sjoerg return(FILTERERR); 7851553Srgrimes } 7861553Srgrimes} 7871553Srgrimes 7881553Srgrimes/* 7891553Srgrimes * Send the daemon control file (cf) and any data files. 7901553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 7911553Srgrimes * 0 if all is well. 7921553Srgrimes */ 7931553Srgrimesstatic int 79431492Swollmansendit(pp, file) 79531492Swollman struct printer *pp; 7961553Srgrimes char *file; 7971553Srgrimes{ 7981553Srgrimes register int i, err = OK; 7991553Srgrimes char *cp, last[BUFSIZ]; 8001553Srgrimes 8011553Srgrimes /* 8021553Srgrimes * open control file 8031553Srgrimes */ 8041553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 8051553Srgrimes return(OK); 8061553Srgrimes /* 8071553Srgrimes * read the control file for work to do 8081553Srgrimes * 8091553Srgrimes * file format -- first character in the line is a command 8101553Srgrimes * rest of the line is the argument. 8111553Srgrimes * commands of interest are: 8121553Srgrimes * 8131553Srgrimes * a-z -- "file name" name of file to print 8141553Srgrimes * U -- "unlink" name of file to remove 8151553Srgrimes * (after we print it. (Pass 2 only)). 8161553Srgrimes */ 8171553Srgrimes 8181553Srgrimes /* 8191553Srgrimes * pass 1 8201553Srgrimes */ 8211553Srgrimes while (getline(cfp)) { 8221553Srgrimes again: 8231553Srgrimes if (line[0] == 'S') { 8241553Srgrimes cp = line+1; 8251553Srgrimes i = 0; 8261553Srgrimes while (*cp >= '0' && *cp <= '9') 8271553Srgrimes i = i * 10 + (*cp++ - '0'); 8281553Srgrimes fdev = i; 8291553Srgrimes cp++; 8301553Srgrimes i = 0; 8311553Srgrimes while (*cp >= '0' && *cp <= '9') 8321553Srgrimes i = i * 10 + (*cp++ - '0'); 8331553Srgrimes fino = i; 83424831Sbrian } else if (line[0] == 'H') { 83524831Sbrian strcpy(fromhost, line+1); 83624831Sbrian if (class[0] == '\0') 83727748Simp strncpy(class, line+1, sizeof(class) - 1); 83824831Sbrian } else if (line[0] == 'P') { 83927748Simp strncpy(logname, line+1, sizeof(logname) - 1); 84031492Swollman if (pp->restricted) { /* restricted */ 84124831Sbrian if (getpwnam(logname) == NULL) { 84231492Swollman sendmail(pp, line+1, NOACCT); 84324831Sbrian err = ERROR; 84424831Sbrian break; 84524831Sbrian } 84624831Sbrian } 84724831Sbrian } else if (line[0] == 'I') { 84827748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 84924831Sbrian } else if (line[0] >= 'a' && line[0] <= 'z') { 8501553Srgrimes strcpy(last, line); 85131492Swollman while ((i = getline(cfp)) != 0) 8521553Srgrimes if (strcmp(last, line)) 8531553Srgrimes break; 85431492Swollman switch (sendfile(pp, '\3', last+1, *last)) { 8551553Srgrimes case OK: 8561553Srgrimes if (i) 8571553Srgrimes goto again; 8581553Srgrimes break; 8591553Srgrimes case REPRINT: 8601553Srgrimes (void) fclose(cfp); 8611553Srgrimes return(REPRINT); 8621553Srgrimes case ACCESS: 86331492Swollman sendmail(pp, logname, ACCESS); 8641553Srgrimes case ERROR: 8651553Srgrimes err = ERROR; 8661553Srgrimes } 8671553Srgrimes break; 8681553Srgrimes } 8691553Srgrimes } 87031492Swollman if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 8711553Srgrimes (void) fclose(cfp); 8721553Srgrimes return(REPRINT); 8731553Srgrimes } 8741553Srgrimes /* 8751553Srgrimes * pass 2 8761553Srgrimes */ 8771553Srgrimes fseek(cfp, 0L, 0); 8781553Srgrimes while (getline(cfp)) 87927748Simp if (line[0] == 'U' && !strchr(line+1, '/')) 8801553Srgrimes (void) unlink(line+1); 8811553Srgrimes /* 8821553Srgrimes * clean-up in case another control file exists 8831553Srgrimes */ 8841553Srgrimes (void) fclose(cfp); 8851553Srgrimes (void) unlink(file); 8861553Srgrimes return(err); 8871553Srgrimes} 8881553Srgrimes 8891553Srgrimes/* 8901553Srgrimes * Send a data file to the remote machine and spool it. 8911553Srgrimes * Return positive if we should try resending. 8921553Srgrimes */ 8931553Srgrimesstatic int 89431492Swollmansendfile(pp, type, file, format) 89531492Swollman struct printer *pp; 8961553Srgrimes int type; 8971553Srgrimes char *file; 89824831Sbrian char format; 8991553Srgrimes{ 9001553Srgrimes register int f, i, amt; 9011553Srgrimes struct stat stb; 9021553Srgrimes char buf[BUFSIZ]; 90324831Sbrian int sizerr, resp, closedpr; 9041553Srgrimes 9051553Srgrimes if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 9061553Srgrimes return(ERROR); 9071553Srgrimes /* 9081553Srgrimes * Check to see if data file is a symbolic link. If so, it should 9091553Srgrimes * still point to the same file or someone is trying to print something 9101553Srgrimes * he shouldn't. 9111553Srgrimes */ 9121553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 9131553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 9141553Srgrimes return(ACCESS); 91524831Sbrian 91624831Sbrian sizerr = 0; 91724831Sbrian closedpr = 0; 91824831Sbrian if (type == '\3') { 91931492Swollman if (pp->filters[LPF_INPUT]) { 92024831Sbrian /* 92124831Sbrian * We're sending something with an ifilter, we have to 92224831Sbrian * run the ifilter and store the output as a 92324831Sbrian * temporary file (tfile)... the protocol requires us 92424831Sbrian * to send the file size 92524831Sbrian */ 92624831Sbrian char *av[15]; 92724831Sbrian int n; 92824831Sbrian int ifilter; 92931492Swollman union wait status; /* XXX */ 93024831Sbrian 93124831Sbrian strcpy(tfile,TFILENAME); 93224831Sbrian if ((tfd = mkstemp(tfile)) == -1) { 93324831Sbrian syslog(LOG_ERR, "mkstemp: %m"); 93424831Sbrian return(ERROR); 93524831Sbrian } 93631492Swollman if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 93731492Swollman av[0] = pp->filters[LPF_INPUT]; 93824831Sbrian else 93924831Sbrian av[0]++; 94024831Sbrian if (format == 'l') 94124831Sbrian av[n=1] = "-c"; 94224831Sbrian else 94324831Sbrian n = 0; 94424831Sbrian av[++n] = width; 94524831Sbrian av[++n] = length; 94624831Sbrian av[++n] = indent; 94724831Sbrian av[++n] = "-n"; 94824831Sbrian av[++n] = logname; 94924831Sbrian av[++n] = "-h"; 95024831Sbrian av[++n] = fromhost; 95131492Swollman av[++n] = pp->acct_file; 95224831Sbrian av[++n] = 0; 95331492Swollman if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 95424831Sbrian dup2(f, 0); 95524831Sbrian dup2(tfd, 1); 95631492Swollman n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 95731492Swollman TEMP_FILE_MODE); 95824831Sbrian if (n >= 0) 95924831Sbrian dup2(n, 2); 96024831Sbrian closelog(); 96131492Swollman closeallfds(3); 96231492Swollman execv(pp->filters[LPF_INPUT], av); 96331492Swollman syslog(LOG_ERR, "cannot execv %s", 96431492Swollman pp->filters[LPF_INPUT]); 96524831Sbrian exit(2); 96624831Sbrian } 96724831Sbrian (void) close(f); 96824831Sbrian if (ifilter < 0) 96924831Sbrian status.w_retcode = 100; 97024831Sbrian else 97124831Sbrian while ((pid = wait((int *)&status)) > 0 && 97224831Sbrian pid != ifilter) 97324831Sbrian ; 97424831Sbrian switch (status.w_retcode) { 97524831Sbrian case 0: 97624831Sbrian break; 97724831Sbrian case 1: 97824831Sbrian unlink(tfile); 97924831Sbrian return(REPRINT); 98024831Sbrian case 2: 98124831Sbrian unlink(tfile); 98224831Sbrian return(ERROR); 98324831Sbrian default: 98424831Sbrian syslog(LOG_WARNING, "%s: filter '%c' exited" 98524831Sbrian " (retcode=%d)", 98631492Swollman pp->printer, format, status.w_retcode); 98724831Sbrian unlink(tfile); 98824831Sbrian return(FILTERERR); 98924831Sbrian } 99024831Sbrian if (fstat(tfd, &stb) < 0) /* the size of tfile */ 99124831Sbrian return(ERROR); 99224831Sbrian f = tfd; 99324831Sbrian lseek(f,0,SEEK_SET); 99424831Sbrian } else if (ofilter) { 99524831Sbrian /* 99624831Sbrian * We're sending something with an ofilter, we have to 99724831Sbrian * store the output as a temporary file (tfile)... the 99824831Sbrian * protocol requires us to send the file size 99924831Sbrian */ 100024831Sbrian int i; 100124831Sbrian for (i = 0; i < stb.st_size; i += BUFSIZ) { 100224831Sbrian amt = BUFSIZ; 100324831Sbrian if (i + amt > stb.st_size) 100424831Sbrian amt = stb.st_size - i; 100524831Sbrian if (sizerr == 0 && read(f, buf, amt) != amt) { 100624831Sbrian sizerr = 1; 100724831Sbrian break; 100824831Sbrian } 100924831Sbrian if (write(ofd, buf, amt) != amt) { 101024831Sbrian (void) close(f); 101124831Sbrian return(REPRINT); 101224831Sbrian } 101324831Sbrian } 101424831Sbrian close(ofd); 101524831Sbrian close(f); 101624831Sbrian while ((i = wait(NULL)) > 0 && i != ofilter) 101724831Sbrian ; 101824831Sbrian ofilter = 0; 101924831Sbrian if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 102031492Swollman openpr(pp); 102124831Sbrian return(ERROR); 102224831Sbrian } 102324831Sbrian f = tfd; 102424831Sbrian lseek(f,0,SEEK_SET); 102524831Sbrian closedpr = 1; 102624831Sbrian } 102724831Sbrian } 102824831Sbrian 10291553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 10301553Srgrimes amt = strlen(buf); 10311553Srgrimes for (i = 0; ; i++) { 10321553Srgrimes if (write(pfd, buf, amt) != amt || 103331492Swollman (resp = response(pp)) < 0 || resp == '\1') { 10341553Srgrimes (void) close(f); 103524831Sbrian if (tfd != -1 && type == '\3') { 103624831Sbrian tfd = -1; 103724831Sbrian unlink(tfile); 103824831Sbrian if (closedpr) 103931492Swollman openpr(pp); 104024831Sbrian } 10411553Srgrimes return(REPRINT); 10421553Srgrimes } else if (resp == '\0') 10431553Srgrimes break; 10441553Srgrimes if (i == 0) 104531492Swollman pstatus(pp, 104631492Swollman "no space on remote; waiting for queue to drain"); 10471553Srgrimes if (i == 10) 10481553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 104931492Swollman pp->printer, pp->remote_host); 10501553Srgrimes sleep(5 * 60); 10511553Srgrimes } 10521553Srgrimes if (i) 105331492Swollman pstatus(pp, "sending to %s", pp->remote_host); 10541553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 10551553Srgrimes amt = BUFSIZ; 10561553Srgrimes if (i + amt > stb.st_size) 10571553Srgrimes amt = stb.st_size - i; 10581553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 10591553Srgrimes sizerr = 1; 10601553Srgrimes if (write(pfd, buf, amt) != amt) { 10611553Srgrimes (void) close(f); 106224831Sbrian if (tfd != -1 && type == '\3') { 106324831Sbrian tfd = -1; 106424831Sbrian unlink(tfile); 106524831Sbrian if (closedpr) 106631492Swollman openpr(pp); 106724831Sbrian } 10681553Srgrimes return(REPRINT); 10691553Srgrimes } 10701553Srgrimes } 10711553Srgrimes 10721553Srgrimes (void) close(f); 107324831Sbrian if (tfd != -1 && type == '\3') { 107424831Sbrian tfd = -1; 107524831Sbrian unlink(tfile); 107624831Sbrian } 10771553Srgrimes if (sizerr) { 107831492Swollman syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 10791553Srgrimes /* tell recvjob to ignore this file */ 10801553Srgrimes (void) write(pfd, "\1", 1); 108124831Sbrian if (closedpr) 108231492Swollman openpr(pp); 10831553Srgrimes return(ERROR); 10841553Srgrimes } 108531492Swollman if (write(pfd, "", 1) != 1 || response(pp)) { 108624831Sbrian if (closedpr) 108731492Swollman openpr(pp); 10881553Srgrimes return(REPRINT); 108924831Sbrian } 109024831Sbrian if (closedpr) 109131492Swollman openpr(pp); 10921553Srgrimes return(OK); 10931553Srgrimes} 10941553Srgrimes 10951553Srgrimes/* 10961553Srgrimes * Check to make sure there have been no errors and that both programs 10971553Srgrimes * are in sync with eachother. 10981553Srgrimes * Return non-zero if the connection was lost. 10991553Srgrimes */ 11001553Srgrimesstatic char 110131492Swollmanresponse(pp) 110231492Swollman const struct printer *pp; 11031553Srgrimes{ 11041553Srgrimes char resp; 11051553Srgrimes 11061553Srgrimes if (read(pfd, &resp, 1) != 1) { 110731492Swollman syslog(LOG_INFO, "%s: lost connection", pp->printer); 11081553Srgrimes return(-1); 11091553Srgrimes } 11101553Srgrimes return(resp); 11111553Srgrimes} 11121553Srgrimes 11131553Srgrimes/* 11141553Srgrimes * Banner printing stuff 11151553Srgrimes */ 11161553Srgrimesstatic void 111731492Swollmanbanner(pp, name1, name2) 111831492Swollman struct printer *pp; 11191553Srgrimes char *name1, *name2; 11201553Srgrimes{ 11211553Srgrimes time_t tvec; 11221553Srgrimes 11231553Srgrimes time(&tvec); 112431492Swollman if (!pp->no_formfeed && !pp->tof) 112531492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 112631492Swollman if (pp->short_banner) { /* short banner only */ 11271553Srgrimes if (class[0]) { 11281553Srgrimes (void) write(ofd, class, strlen(class)); 11291553Srgrimes (void) write(ofd, ":", 1); 11301553Srgrimes } 11311553Srgrimes (void) write(ofd, name1, strlen(name1)); 11321553Srgrimes (void) write(ofd, " Job: ", 7); 11331553Srgrimes (void) write(ofd, name2, strlen(name2)); 11341553Srgrimes (void) write(ofd, " Date: ", 8); 11351553Srgrimes (void) write(ofd, ctime(&tvec), 24); 11361553Srgrimes (void) write(ofd, "\n", 1); 11371553Srgrimes } else { /* normal banner */ 11381553Srgrimes (void) write(ofd, "\n\n\n", 3); 113931492Swollman scan_out(pp, ofd, name1, '\0'); 11401553Srgrimes (void) write(ofd, "\n\n", 2); 114131492Swollman scan_out(pp, ofd, name2, '\0'); 11421553Srgrimes if (class[0]) { 11431553Srgrimes (void) write(ofd,"\n\n\n",3); 114431492Swollman scan_out(pp, ofd, class, '\0'); 11451553Srgrimes } 11461553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 11471553Srgrimes (void) write(ofd, name2, strlen(name2)); 11481553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 11491553Srgrimes (void) write(ofd, ctime(&tvec), 24); 11501553Srgrimes (void) write(ofd, "\n", 1); 11511553Srgrimes } 115231492Swollman if (!pp->no_formfeed) 115331492Swollman (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 115431492Swollman pp->tof = 1; 11551553Srgrimes} 11561553Srgrimes 11571553Srgrimesstatic char * 11581553Srgrimesscnline(key, p, c) 11591553Srgrimes register int key; 11601553Srgrimes register char *p; 11611553Srgrimes int c; 11621553Srgrimes{ 116339084Swollman register int scnwidth; 11641553Srgrimes 11651553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 11661553Srgrimes key <<= 1; 11671553Srgrimes *p++ = key & 0200 ? c : BACKGND; 11681553Srgrimes } 11691553Srgrimes return (p); 11701553Srgrimes} 11711553Srgrimes 11721553Srgrimes#define TRC(q) (((q)-' ')&0177) 11731553Srgrimes 11741553Srgrimesstatic void 117531492Swollmanscan_out(pp, scfd, scsp, dlm) 117631492Swollman struct printer *pp; 11771553Srgrimes int scfd, dlm; 11781553Srgrimes char *scsp; 11791553Srgrimes{ 11801553Srgrimes register char *strp; 118139084Swollman register int nchrs, j; 11821553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 11831553Srgrimes int d, scnhgt; 11841553Srgrimes 11851553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 11861553Srgrimes strp = &outbuf[0]; 11871553Srgrimes sp = scsp; 11881553Srgrimes for (nchrs = 0; ; ) { 11891553Srgrimes d = dropit(c = TRC(cc = *sp++)); 11901553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 11911553Srgrimes for (j = WIDTH; --j;) 11921553Srgrimes *strp++ = BACKGND; 11931553Srgrimes else 119431492Swollman strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 119531492Swollman if (*sp == dlm || *sp == '\0' || 119631492Swollman nchrs++ >= pp->page_width/(WIDTH+1)-1) 11971553Srgrimes break; 11981553Srgrimes *strp++ = BACKGND; 11991553Srgrimes *strp++ = BACKGND; 12001553Srgrimes } 12011553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 12021553Srgrimes ; 12031553Srgrimes strp++; 12048857Srgrimes *strp++ = '\n'; 12051553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 12061553Srgrimes } 12071553Srgrimes} 12081553Srgrimes 12091553Srgrimesstatic int 12101553Srgrimesdropit(c) 12111553Srgrimes int c; 12121553Srgrimes{ 12131553Srgrimes switch(c) { 12141553Srgrimes 12151553Srgrimes case TRC('_'): 12161553Srgrimes case TRC(';'): 12171553Srgrimes case TRC(','): 12181553Srgrimes case TRC('g'): 12191553Srgrimes case TRC('j'): 12201553Srgrimes case TRC('p'): 12211553Srgrimes case TRC('q'): 12221553Srgrimes case TRC('y'): 12231553Srgrimes return (DROP); 12241553Srgrimes 12251553Srgrimes default: 12261553Srgrimes return (0); 12271553Srgrimes } 12281553Srgrimes} 12291553Srgrimes 12301553Srgrimes/* 12311553Srgrimes * sendmail --- 12321553Srgrimes * tell people about job completion 12331553Srgrimes */ 12341553Srgrimesstatic void 123531492Swollmansendmail(pp, user, bombed) 123631492Swollman struct printer *pp; 12371553Srgrimes char *user; 12381553Srgrimes int bombed; 12391553Srgrimes{ 12401553Srgrimes register int i; 12411553Srgrimes int p[2], s; 12421553Srgrimes register char *cp; 12431553Srgrimes struct stat stb; 12441553Srgrimes FILE *fp; 12451553Srgrimes 12461553Srgrimes pipe(p); 124731492Swollman if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 12481553Srgrimes dup2(p[0], 0); 12498094Sjkh closelog(); 125031492Swollman closeallfds(3); 125127635Simp if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 12521553Srgrimes cp++; 125331492Swollman else 12541553Srgrimes cp = _PATH_SENDMAIL; 125527757Simp execl(_PATH_SENDMAIL, cp, "-t", 0); 125631492Swollman _exit(0); 12571553Srgrimes } else if (s > 0) { /* parent */ 12581553Srgrimes dup2(p[1], 1); 12591553Srgrimes printf("To: %s@%s\n", user, fromhost); 126031492Swollman printf("Subject: %s printer job \"%s\"\n", pp->printer, 126115648Sjoerg *jobname ? jobname : "<unknown>"); 126215648Sjoerg printf("Reply-To: root@%s\n\n", host); 12631553Srgrimes printf("Your printer job "); 12641553Srgrimes if (*jobname) 12651553Srgrimes printf("(%s) ", jobname); 126631492Swollman 126731492Swollman cp = "XXX compiler confusion"; /* XXX shut GCC up */ 12681553Srgrimes switch (bombed) { 12691553Srgrimes case OK: 12701553Srgrimes printf("\ncompleted successfully\n"); 127115648Sjoerg cp = "OK"; 12721553Srgrimes break; 12731553Srgrimes default: 12741553Srgrimes case FATALERR: 12751553Srgrimes printf("\ncould not be printed\n"); 127615648Sjoerg cp = "FATALERR"; 12771553Srgrimes break; 12781553Srgrimes case NOACCT: 12791553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 128015648Sjoerg cp = "NOACCT"; 12811553Srgrimes break; 12821553Srgrimes case FILTERERR: 12831553Srgrimes if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 12841553Srgrimes (fp = fopen(tempfile, "r")) == NULL) { 128515648Sjoerg printf("\nhad some errors and may not have printed\n"); 12861553Srgrimes break; 12871553Srgrimes } 128815648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 12891553Srgrimes while ((i = getc(fp)) != EOF) 12901553Srgrimes putchar(i); 12911553Srgrimes (void) fclose(fp); 129215648Sjoerg cp = "FILTERERR"; 12931553Srgrimes break; 12941553Srgrimes case ACCESS: 12951553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 129615648Sjoerg cp = "ACCESS"; 12971553Srgrimes } 12981553Srgrimes fflush(stdout); 12991553Srgrimes (void) close(1); 130031492Swollman } else { 130131492Swollman syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 130231492Swollman return; 13031553Srgrimes } 13041553Srgrimes (void) close(p[0]); 13051553Srgrimes (void) close(p[1]); 130615648Sjoerg wait(NULL); 130715648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 130831492Swollman user, *jobname ? jobname : "<unknown>", pp->printer, cp); 13091553Srgrimes} 13101553Srgrimes 13111553Srgrimes/* 13121553Srgrimes * dofork - fork with retries on failure 13131553Srgrimes */ 13141553Srgrimesstatic int 131531492Swollmandofork(pp, action) 131631492Swollman const struct printer *pp; 13171553Srgrimes int action; 13181553Srgrimes{ 13191553Srgrimes register int i, pid; 13201553Srgrimes 13211553Srgrimes for (i = 0; i < 20; i++) { 13221553Srgrimes if ((pid = fork()) < 0) { 13231553Srgrimes sleep((unsigned)(i*i)); 13241553Srgrimes continue; 13251553Srgrimes } 13261553Srgrimes /* 13271553Srgrimes * Child should run as daemon instead of root 13281553Srgrimes */ 132915648Sjoerg if (pid == 0) 133031492Swollman setuid(pp->daemon_user); 13311553Srgrimes return(pid); 13321553Srgrimes } 13331553Srgrimes syslog(LOG_ERR, "can't fork"); 13341553Srgrimes 13351553Srgrimes switch (action) { 13361553Srgrimes case DORETURN: 13371553Srgrimes return (-1); 13381553Srgrimes default: 13391553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 13401553Srgrimes /*FALL THRU*/ 13411553Srgrimes case DOABORT: 13421553Srgrimes exit(1); 13431553Srgrimes } 13441553Srgrimes /*NOTREACHED*/ 13451553Srgrimes} 13461553Srgrimes 13471553Srgrimes/* 13481553Srgrimes * Kill child processes to abort current job. 13491553Srgrimes */ 13501553Srgrimesstatic void 13511553Srgrimesabortpr(signo) 13521553Srgrimes int signo; 13531553Srgrimes{ 13541553Srgrimes (void) unlink(tempfile); 13551553Srgrimes kill(0, SIGINT); 13561553Srgrimes if (ofilter > 0) 13571553Srgrimes kill(ofilter, SIGCONT); 13581553Srgrimes while (wait(NULL) > 0) 13591553Srgrimes ; 136024831Sbrian if (ofilter > 0 && tfd != -1) 136124831Sbrian unlink(tfile); 13621553Srgrimes exit(0); 13631553Srgrimes} 13641553Srgrimes 13651553Srgrimesstatic void 136631492Swollmaninit(pp) 136731492Swollman struct printer *pp; 13681553Srgrimes{ 13691553Srgrimes char *s; 13701553Srgrimes 137131492Swollman sprintf(&width[2], "%ld", pp->page_width); 137231492Swollman sprintf(&length[2], "%ld", pp->page_length); 137331492Swollman sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 137431492Swollman sprintf(&pxlength[2], "%ld", pp->page_plength); 137531492Swollman if ((s = checkremote(pp)) != 0) { 137631492Swollman syslog(LOG_WARNING, "%s", s); 137731492Swollman free(s); 137831492Swollman } 137931492Swollman} 138031492Swollman 138131492Swollmanvoid 138231492Swollmanstartprinting(printer) 138331492Swollman const char *printer; 138431492Swollman{ 138531492Swollman struct printer myprinter, *pp = &myprinter; 138631492Swollman int status; 138731492Swollman 138831492Swollman init_printer(pp); 138931492Swollman status = getprintcap(printer, pp); 139031492Swollman switch(status) { 139131492Swollman case PCAPERR_OSERR: 139231492Swollman syslog(LOG_ERR, "can't open printer description file: %m"); 13931553Srgrimes exit(1); 139431492Swollman case PCAPERR_NOTFOUND: 13951553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 13961553Srgrimes exit(1); 139731492Swollman case PCAPERR_TCLOOP: 139831492Swollman fatal(pp, "potential reference loop detected in printcap file"); 139931492Swollman default: 140031492Swollman break; 140131492Swollman } 140231492Swollman printjob(pp); 14031553Srgrimes} 14041553Srgrimes 14051553Srgrimes/* 14061553Srgrimes * Acquire line printer or remote connection. 14071553Srgrimes */ 14081553Srgrimesstatic void 140931492Swollmanopenpr(pp) 141031492Swollman const struct printer *pp; 14111553Srgrimes{ 141231492Swollman int p[2]; 141315648Sjoerg char *cp; 14141553Srgrimes 141531492Swollman if (pp->remote) { 141631492Swollman openrem(pp); 141731492Swollman } else if (*pp->lp) { 141831492Swollman if ((cp = strchr(pp->lp, '@')) != NULL) 141931492Swollman opennet(pp); 142015648Sjoerg else 142131492Swollman opentty(pp); 14221553Srgrimes } else { 14231553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 142431492Swollman pp->printer); 14251553Srgrimes exit(1); 14261553Srgrimes } 142715648Sjoerg 14281553Srgrimes /* 14291553Srgrimes * Start up an output filter, if needed. 14301553Srgrimes */ 143131492Swollman if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 14321553Srgrimes pipe(p); 143331492Swollman if (pp->remote) { 143431492Swollman strcpy(tfile, TFILENAME); 143524831Sbrian tfd = mkstemp(tfile); 143624831Sbrian } 143731492Swollman if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 14381553Srgrimes dup2(p[0], 0); /* pipe is std in */ 143924831Sbrian /* tfile/printer is stdout */ 144031492Swollman dup2(pp->remote ? tfd : pfd, 1); 14418094Sjkh closelog(); 144231492Swollman closeallfds(3); 144331492Swollman if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 144431492Swollman cp = pp->filters[LPF_OUTPUT]; 14451553Srgrimes else 14461553Srgrimes cp++; 144731492Swollman execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); 144831492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, 144931492Swollman pp->filters[LPF_OUTPUT]); 14501553Srgrimes exit(1); 14511553Srgrimes } 14521553Srgrimes (void) close(p[0]); /* close input side */ 14531553Srgrimes ofd = p[1]; /* use pipe for output */ 14541553Srgrimes } else { 14551553Srgrimes ofd = pfd; 14561553Srgrimes ofilter = 0; 14571553Srgrimes } 14581553Srgrimes} 14591553Srgrimes 146015648Sjoerg/* 146115648Sjoerg * Printer connected directly to the network 146215648Sjoerg * or to a terminal server on the net 146315648Sjoerg */ 146415648Sjoergstatic void 146531492Swollmanopennet(pp) 146631492Swollman const struct printer *pp; 146715648Sjoerg{ 146815648Sjoerg register int i; 146931492Swollman int resp; 147031492Swollman u_long port; 147131492Swollman char *ep; 147230407Sjoerg void (*savealrm)(int); 147315648Sjoerg 147431492Swollman port = strtoul(pp->lp, &ep, 0); 147538470Sbrian if (*ep != '@' || port > 65535) { 147631492Swollman syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 147731492Swollman pp->lp); 147815648Sjoerg exit(1); 147915648Sjoerg } 148031492Swollman ep++; 148115648Sjoerg 148215648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 148315648Sjoerg resp = -1; 148430407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 148531492Swollman alarm(pp->conn_timeout); 148631492Swollman pfd = getport(pp, ep, port); 148731020Sjoerg alarm(0); 148830407Sjoerg (void)signal(SIGALRM, savealrm); 148915648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 149015648Sjoerg resp = 1; 149115648Sjoerg else if (pfd >= 0) { 149215648Sjoerg /* 149315648Sjoerg * need to delay a bit for rs232 lines 149415648Sjoerg * to stabilize in case printer is 149515648Sjoerg * connected via a terminal server 149615648Sjoerg */ 149715648Sjoerg delay(500); 149815648Sjoerg break; 149915648Sjoerg } 150015648Sjoerg if (i == 1) { 150131492Swollman if (resp < 0) 150231492Swollman pstatus(pp, "waiting for %s to come up", 150331492Swollman pp->lp); 150431492Swollman else 150531492Swollman pstatus(pp, 150631492Swollman "waiting for access to printer on %s", 150731492Swollman pp->lp); 150815648Sjoerg } 150915648Sjoerg sleep(i); 151015648Sjoerg } 151131492Swollman pstatus(pp, "sending to %s port %d", ep, port); 151215648Sjoerg} 151315648Sjoerg 151415648Sjoerg/* 151515648Sjoerg * Printer is connected to an RS232 port on this host 151615648Sjoerg */ 151715648Sjoergstatic void 151831492Swollmanopentty(pp) 151931492Swollman const struct printer *pp; 152015648Sjoerg{ 152115648Sjoerg register int i; 152215648Sjoerg 152315648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 152431492Swollman pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 152515648Sjoerg if (pfd >= 0) { 152615648Sjoerg delay(500); 152715648Sjoerg break; 152815648Sjoerg } 152915648Sjoerg if (errno == ENOENT) { 153031492Swollman syslog(LOG_ERR, "%s: %m", pp->lp); 153115648Sjoerg exit(1); 153215648Sjoerg } 153315648Sjoerg if (i == 1) 153431492Swollman pstatus(pp, 153531492Swollman "waiting for %s to become ready (offline?)", 153631492Swollman pp->printer); 153715648Sjoerg sleep(i); 153815648Sjoerg } 153915648Sjoerg if (isatty(pfd)) 154031492Swollman setty(pp); 154131492Swollman pstatus(pp, "%s is ready and printing", pp->printer); 154215648Sjoerg} 154315648Sjoerg 154415648Sjoerg/* 154515648Sjoerg * Printer is on a remote host 154615648Sjoerg */ 154715648Sjoergstatic void 154831492Swollmanopenrem(pp) 154931492Swollman const struct printer *pp; 155015648Sjoerg{ 155131492Swollman register int i; 155227748Simp int resp; 155330407Sjoerg void (*savealrm)(int); 155415648Sjoerg 155515648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 155615648Sjoerg resp = -1; 155730407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 155831492Swollman alarm(pp->conn_timeout); 155931492Swollman pfd = getport(pp, pp->remote_host, 0); 156031020Sjoerg alarm(0); 156130407Sjoerg (void)signal(SIGALRM, savealrm); 156215648Sjoerg if (pfd >= 0) { 156331492Swollman if ((writel(pfd, "\2", pp->remote_queue, "\n", 156431492Swollman (char *)0) 156531492Swollman == 2 + strlen(pp->remote_queue)) 156631492Swollman && (resp = response(pp)) == 0) 156715648Sjoerg break; 156815648Sjoerg (void) close(pfd); 156915648Sjoerg } 157015648Sjoerg if (i == 1) { 157115648Sjoerg if (resp < 0) 157231492Swollman pstatus(pp, "waiting for %s to come up", 157331492Swollman pp->remote_host); 157415648Sjoerg else { 157531492Swollman pstatus(pp, 157631492Swollman "waiting for queue to be enabled on %s", 157731492Swollman pp->remote_host); 157815648Sjoerg i = 256; 157915648Sjoerg } 158015648Sjoerg } 158115648Sjoerg sleep(i); 158215648Sjoerg } 158331492Swollman pstatus(pp, "sending to %s", pp->remote_host); 158415648Sjoerg} 158515648Sjoerg 15861553Srgrimes/* 15871553Srgrimes * setup tty lines. 15881553Srgrimes */ 15891553Srgrimesstatic void 159031492Swollmansetty(pp) 159131492Swollman const struct printer *pp; 15921553Srgrimes{ 159315032Ssef struct termios ttybuf; 15941553Srgrimes 15951553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 159631492Swollman syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 15971553Srgrimes exit(1); 15981553Srgrimes } 159915032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 160031492Swollman syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 16011553Srgrimes exit(1); 16021553Srgrimes } 160331492Swollman if (pp->baud_rate > 0) 160431492Swollman cfsetspeed(&ttybuf, pp->baud_rate); 160531492Swollman if (pp->mode_set) { 160631492Swollman char *s = strdup(pp->mode_set), *tmp; 160715032Ssef 160831492Swollman while ((tmp = strsep(&s, ",")) != NULL) { 160939084Swollman (void) msearch(tmp, &ttybuf); 16101553Srgrimes } 16111553Srgrimes } 161231492Swollman if (pp->mode_set != 0 || pp->baud_rate > 0) { 161315032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 161431492Swollman syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 16151553Srgrimes } 16161553Srgrimes } 16171553Srgrimes} 16181553Srgrimes 161927757Simp#ifdef __STDC__ 16201553Srgrimes#include <stdarg.h> 16211553Srgrimes#else 16221553Srgrimes#include <varargs.h> 16231553Srgrimes#endif 16241553Srgrimes 162515648Sjoergstatic void 162627757Simp#ifdef __STDC__ 162731492Swollmanpstatus(const struct printer *pp, const char *msg, ...) 16281553Srgrimes#else 162931492Swollmanpstatus(pp, msg, va_alist) 163031492Swollman const struct printer *pp; 16311553Srgrimes char *msg; 16321553Srgrimes va_dcl 16331553Srgrimes#endif 16341553Srgrimes{ 163531492Swollman int fd; 163631492Swollman char *buf; 16371553Srgrimes va_list ap; 163827757Simp#ifdef __STDC__ 16391553Srgrimes va_start(ap, msg); 16401553Srgrimes#else 16411553Srgrimes va_start(ap); 16421553Srgrimes#endif 16431553Srgrimes 16441553Srgrimes umask(0); 164531492Swollman fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 164631492Swollman if (fd < 0) { 164731492Swollman syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 16481553Srgrimes exit(1); 16491553Srgrimes } 16501553Srgrimes ftruncate(fd, 0); 165131492Swollman vasprintf(&buf, msg, ap); 16521553Srgrimes va_end(ap); 165331492Swollman writel(fd, buf, "\n", (char *)0); 165431492Swollman close(fd); 165531492Swollman free(buf); 16561553Srgrimes} 165730407Sjoerg 165830407Sjoergvoid 165930407Sjoergalarmhandler(signo) 166030407Sjoerg{ 166130407Sjoerg /* ignored */ 166230407Sjoerg} 1663