printjob.c revision 15703
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 361553Srgrimesstatic 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 4215648Sjoergstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 431553Srgrimes#endif /* not lint */ 441553Srgrimes 451553Srgrimes 461553Srgrimes/* 471553Srgrimes * printjob -- print jobs in the queue. 481553Srgrimes * 491553Srgrimes * NOTE: the lock file is used to pass information to lpq and lprm. 501553Srgrimes * it does not need to be removed because file locks are dynamic. 511553Srgrimes */ 521553Srgrimes 531553Srgrimes#include <sys/param.h> 541553Srgrimes#include <sys/wait.h> 551553Srgrimes#include <sys/stat.h> 561553Srgrimes#include <sys/types.h> 571553Srgrimes 581553Srgrimes#include <pwd.h> 591553Srgrimes#include <unistd.h> 601553Srgrimes#include <signal.h> 611553Srgrimes#include <syslog.h> 621553Srgrimes#include <fcntl.h> 631553Srgrimes#include <dirent.h> 641553Srgrimes#include <errno.h> 651553Srgrimes#include <stdio.h> 661553Srgrimes#include <string.h> 671553Srgrimes#include <stdlib.h> 6815032Ssef#include <sys/ioctl.h> 6915032Ssef#include <termios.h> 7015703Sjoerg#include <time.h> 711553Srgrimes#include "lp.h" 721553Srgrimes#include "lp.local.h" 731553Srgrimes#include "pathnames.h" 741553Srgrimes#include "extern.h" 751553Srgrimes 761553Srgrimes#define DORETURN 0 /* absorb fork error */ 771553Srgrimes#define DOABORT 1 /* abort if dofork fails */ 781553Srgrimes 791553Srgrimes/* 801553Srgrimes * Error tokens 811553Srgrimes */ 821553Srgrimes#define REPRINT -2 831553Srgrimes#define ERROR -1 841553Srgrimes#define OK 0 851553Srgrimes#define FATALERR 1 861553Srgrimes#define NOACCT 2 871553Srgrimes#define FILTERERR 3 881553Srgrimes#define ACCESS 4 891553Srgrimes 901553Srgrimesstatic dev_t fdev; /* device of file pointed to by symlink */ 911553Srgrimesstatic ino_t fino; /* inode of file pointed to by symlink */ 921553Srgrimesstatic FILE *cfp; /* control file */ 931553Srgrimesstatic int child; /* id of any filters */ 941553Srgrimesstatic int lfd; /* lock file descriptor */ 951553Srgrimesstatic int ofd; /* output filter file descriptor */ 961553Srgrimesstatic int ofilter; /* id of output filter, if any */ 971553Srgrimesstatic int pfd; /* prstatic inter file descriptor */ 981553Srgrimesstatic int pid; /* pid of lpd process */ 991553Srgrimesstatic int prchild; /* id of pr process */ 1001553Srgrimesstatic char title[80]; /* ``pr'' title */ 1011553Srgrimesstatic int tof; /* true if at top of form */ 1021553Srgrimes 1031553Srgrimesstatic char class[32]; /* classification field */ 1041553Srgrimesstatic char fromhost[32]; /* user's host machine */ 1051553Srgrimes /* indentation size in static characters */ 1068857Srgrimesstatic char indent[10] = "-i0"; 1071553Srgrimesstatic char jobname[100]; /* job or file name */ 1081553Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1091553Srgrimesstatic char logname[32]; /* user's login name */ 1101553Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1111553Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 1121553Srgrimesstatic char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 1131553Srgrimesstatic char width[10] = "-w"; /* page width in static characters */ 1141553Srgrimes 1151553Srgrimesstatic void abortpr __P((int)); 1161553Srgrimesstatic void banner __P((char *, char *)); 1171553Srgrimesstatic int dofork __P((int)); 1181553Srgrimesstatic int dropit __P((int)); 1191553Srgrimesstatic void init __P((void)); 1201553Srgrimesstatic void openpr __P((void)); 12115648Sjoergstatic void opennet __P((char *)); 12215648Sjoergstatic void opentty __P((void)); 12315648Sjoergstatic void openrem __P((void)); 1241553Srgrimesstatic int print __P((int, char *)); 1251553Srgrimesstatic int printit __P((char *)); 1261553Srgrimesstatic void pstatus __P((const char *, ...)); 1271553Srgrimesstatic char response __P((void)); 1281553Srgrimesstatic void scan_out __P((int, char *, int)); 1291553Srgrimesstatic char *scnline __P((int, char *, int)); 1301553Srgrimesstatic int sendfile __P((int, char *)); 1311553Srgrimesstatic int sendit __P((char *)); 1321553Srgrimesstatic void sendmail __P((char *, int)); 1331553Srgrimesstatic void setty __P((void)); 1341553Srgrimes 1351553Srgrimesvoid 1361553Srgrimesprintjob() 1371553Srgrimes{ 1381553Srgrimes struct stat stb; 1391553Srgrimes register struct queue *q, **qp; 1401553Srgrimes struct queue **queue; 1411553Srgrimes register int i, nitems; 14215648Sjoerg off_t pidoff; 14315648Sjoerg int errcnt, count = 0; 1441553Srgrimes 1451553Srgrimes init(); /* set up capabilities */ 1461553Srgrimes (void) write(1, "", 1); /* ack that daemon is started */ 1471553Srgrimes (void) close(2); /* set up log file */ 1481553Srgrimes if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 1491553Srgrimes syslog(LOG_ERR, "%s: %m", LF); 1501553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1511553Srgrimes } 1521553Srgrimes setgid(getegid()); 1531553Srgrimes pid = getpid(); /* for use with lprm */ 1541553Srgrimes setpgrp(0, pid); 1551553Srgrimes signal(SIGHUP, abortpr); 1561553Srgrimes signal(SIGINT, abortpr); 1571553Srgrimes signal(SIGQUIT, abortpr); 1581553Srgrimes signal(SIGTERM, abortpr); 1591553Srgrimes 1601553Srgrimes (void) mktemp(tempfile); 1611553Srgrimes 1621553Srgrimes /* 1631553Srgrimes * uses short form file names 1641553Srgrimes */ 1651553Srgrimes if (chdir(SD) < 0) { 1661553Srgrimes syslog(LOG_ERR, "%s: %m", SD); 1671553Srgrimes exit(1); 1681553Srgrimes } 1691553Srgrimes if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 1701553Srgrimes exit(0); /* printing disabled */ 1711553Srgrimes lfd = open(LO, O_WRONLY|O_CREAT, 0644); 1721553Srgrimes if (lfd < 0) { 1731553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1741553Srgrimes exit(1); 1751553Srgrimes } 1761553Srgrimes if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 1771553Srgrimes if (errno == EWOULDBLOCK) /* active deamon present */ 1781553Srgrimes exit(0); 1791553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1801553Srgrimes exit(1); 1811553Srgrimes } 1821553Srgrimes ftruncate(lfd, 0); 1831553Srgrimes /* 1841553Srgrimes * write process id for others to know 1851553Srgrimes */ 1861553Srgrimes sprintf(line, "%u\n", pid); 1871553Srgrimes pidoff = i = strlen(line); 1881553Srgrimes if (write(lfd, line, i) != i) { 1891553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1901553Srgrimes exit(1); 1911553Srgrimes } 1921553Srgrimes /* 1931553Srgrimes * search the spool directory for work and sort by queue order. 1941553Srgrimes */ 1951553Srgrimes if ((nitems = getq(&queue)) < 0) { 1961553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 1971553Srgrimes exit(1); 1981553Srgrimes } 1991553Srgrimes if (nitems == 0) /* no work to do */ 2001553Srgrimes exit(0); 2011553Srgrimes if (stb.st_mode & 01) { /* reset queue flag */ 2021553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2031553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2041553Srgrimes } 2051553Srgrimes openpr(); /* open printer or remote */ 2061553Srgrimesagain: 2071553Srgrimes /* 2081553Srgrimes * we found something to do now do it -- 2091553Srgrimes * write the name of the current control file into the lock file 2101553Srgrimes * so the spool queue program can tell what we're working on 2111553Srgrimes */ 2121553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2131553Srgrimes q = *qp++; 2141553Srgrimes if (stat(q->q_name, &stb) < 0) 2151553Srgrimes continue; 21615648Sjoerg errcnt = 0; 2171553Srgrimes restart: 21815648Sjoerg (void) lseek(lfd, pidoff, 0); 2191553Srgrimes (void) sprintf(line, "%s\n", q->q_name); 2201553Srgrimes i = strlen(line); 2211553Srgrimes if (write(lfd, line, i) != i) 2221553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2231553Srgrimes if (!remote) 2241553Srgrimes i = printit(q->q_name); 2251553Srgrimes else 2261553Srgrimes i = sendit(q->q_name); 2271553Srgrimes /* 2281553Srgrimes * Check to see if we are supposed to stop printing or 2291553Srgrimes * if we are to rebuild the queue. 2301553Srgrimes */ 2311553Srgrimes if (fstat(lfd, &stb) == 0) { 2321553Srgrimes /* stop printing before starting next job? */ 2331553Srgrimes if (stb.st_mode & 0100) 2341553Srgrimes goto done; 2351553Srgrimes /* rebuild queue (after lpc topq) */ 2361553Srgrimes if (stb.st_mode & 01) { 2371553Srgrimes for (free((char *) q); nitems--; free((char *) q)) 2381553Srgrimes q = *qp++; 2391553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2401553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 2411553Srgrimes printer, LO); 2421553Srgrimes break; 2431553Srgrimes } 2441553Srgrimes } 2451553Srgrimes if (i == OK) /* file ok and printed */ 2461553Srgrimes count++; 24715648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 24815648Sjoerg /* try reprinting the job */ 2491553Srgrimes syslog(LOG_INFO, "restarting %s", printer); 2501553Srgrimes if (ofilter > 0) { 2511553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2521553Srgrimes (void) close(ofd); 25315648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2541553Srgrimes ; 2551553Srgrimes ofilter = 0; 2561553Srgrimes } 2571553Srgrimes (void) close(pfd); /* close printer */ 2581553Srgrimes if (ftruncate(lfd, pidoff) < 0) 2591553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 2601553Srgrimes openpr(); /* try to reopen printer */ 2611553Srgrimes goto restart; 26215648Sjoerg } else { 26315648Sjoerg syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 26415648Sjoerg remote ? "sent to remote host" : "printed", q->q_name); 26515648Sjoerg if (i == REPRINT) { 26615648Sjoerg /* insure we don't attempt this job again */ 26715648Sjoerg (void) unlink(q->q_name); 26815648Sjoerg q->q_name[0] = 'd'; 26915648Sjoerg (void) unlink(q->q_name); 27015648Sjoerg if (logname[0]) 27115648Sjoerg sendmail(logname, FATALERR); 27215648Sjoerg } 2731553Srgrimes } 2741553Srgrimes } 2751553Srgrimes free((char *) queue); 2761553Srgrimes /* 2771553Srgrimes * search the spool directory for more work. 2781553Srgrimes */ 2791553Srgrimes if ((nitems = getq(&queue)) < 0) { 2801553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 2811553Srgrimes exit(1); 2821553Srgrimes } 2831553Srgrimes if (nitems == 0) { /* no more work to do */ 2841553Srgrimes done: 2851553Srgrimes if (count > 0) { /* Files actually printed */ 2861553Srgrimes if (!SF && !tof) 2871553Srgrimes (void) write(ofd, FF, strlen(FF)); 2881553Srgrimes if (TR != NULL) /* output trailer */ 2891553Srgrimes (void) write(ofd, TR, strlen(TR)); 2901553Srgrimes } 2911553Srgrimes (void) unlink(tempfile); 2921553Srgrimes exit(0); 2931553Srgrimes } 2941553Srgrimes goto again; 2951553Srgrimes} 2961553Srgrimes 2971553Srgrimeschar fonts[4][50]; /* fonts for troff */ 2981553Srgrimes 2991553Srgrimeschar ifonts[4][40] = { 3001553Srgrimes _PATH_VFONTR, 3011553Srgrimes _PATH_VFONTI, 3021553Srgrimes _PATH_VFONTB, 3031553Srgrimes _PATH_VFONTS, 3041553Srgrimes}; 3051553Srgrimes 3061553Srgrimes/* 3071553Srgrimes * The remaining part is the reading of the control file (cf) 3081553Srgrimes * and performing the various actions. 3091553Srgrimes */ 3101553Srgrimesstatic int 3111553Srgrimesprintit(file) 3121553Srgrimes char *file; 3131553Srgrimes{ 3141553Srgrimes register int i; 3151553Srgrimes char *cp; 3161553Srgrimes int bombed = OK; 3171553Srgrimes 3181553Srgrimes /* 3191553Srgrimes * open control file; ignore if no longer there. 3201553Srgrimes */ 3211553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 3221553Srgrimes syslog(LOG_INFO, "%s: %s: %m", printer, file); 3231553Srgrimes return(OK); 3241553Srgrimes } 3251553Srgrimes /* 3261553Srgrimes * Reset troff fonts. 3271553Srgrimes */ 3281553Srgrimes for (i = 0; i < 4; i++) 3291553Srgrimes strcpy(fonts[i], ifonts[i]); 3301553Srgrimes sprintf(&width[2], "%d", PW); 3311553Srgrimes strcpy(indent+2, "0"); 3321553Srgrimes 3331553Srgrimes /* 3341553Srgrimes * read the control file for work to do 3351553Srgrimes * 3361553Srgrimes * file format -- first character in the line is a command 3371553Srgrimes * rest of the line is the argument. 3381553Srgrimes * valid commands are: 3391553Srgrimes * 3401553Srgrimes * S -- "stat info" for symbolic link protection 3411553Srgrimes * J -- "job name" on banner page 3421553Srgrimes * C -- "class name" on banner page 3431553Srgrimes * L -- "literal" user's name to print on banner 3441553Srgrimes * T -- "title" for pr 3451553Srgrimes * H -- "host name" of machine where lpr was done 3461553Srgrimes * P -- "person" user's login name 3471553Srgrimes * I -- "indent" amount to indent output 34815648Sjoerg * R -- laser dpi "resolution" 3491553Srgrimes * f -- "file name" name of text file to print 3501553Srgrimes * l -- "file name" text file with control chars 3511553Srgrimes * p -- "file name" text file to print with pr(1) 3521553Srgrimes * t -- "file name" troff(1) file to print 3531553Srgrimes * n -- "file name" ditroff(1) file to print 3541553Srgrimes * d -- "file name" dvi file to print 3551553Srgrimes * g -- "file name" plot(1G) file to print 3561553Srgrimes * v -- "file name" plain raster file to print 3571553Srgrimes * c -- "file name" cifplot file to print 3581553Srgrimes * 1 -- "R font file" for troff 3591553Srgrimes * 2 -- "I font file" for troff 3601553Srgrimes * 3 -- "B font file" for troff 3611553Srgrimes * 4 -- "S font file" for troff 3621553Srgrimes * N -- "name" of file (used by lpq) 3631553Srgrimes * U -- "unlink" name of file to remove 3641553Srgrimes * (after we print it. (Pass 2 only)). 3651553Srgrimes * M -- "mail" to user when done printing 3661553Srgrimes * 3671553Srgrimes * getline reads a line and expands tabs to blanks 3681553Srgrimes */ 3691553Srgrimes 3701553Srgrimes /* pass 1 */ 3711553Srgrimes 3721553Srgrimes while (getline(cfp)) 3731553Srgrimes switch (line[0]) { 3741553Srgrimes case 'H': 3751553Srgrimes strcpy(fromhost, line+1); 3761553Srgrimes if (class[0] == '\0') 3771553Srgrimes strncpy(class, line+1, sizeof(class)-1); 3781553Srgrimes continue; 3791553Srgrimes 3801553Srgrimes case 'P': 3811553Srgrimes strncpy(logname, line+1, sizeof(logname)-1); 3821553Srgrimes if (RS) { /* restricted */ 3831553Srgrimes if (getpwnam(logname) == NULL) { 3841553Srgrimes bombed = NOACCT; 3851553Srgrimes sendmail(line+1, bombed); 3861553Srgrimes goto pass2; 3871553Srgrimes } 3881553Srgrimes } 3891553Srgrimes continue; 3901553Srgrimes 3911553Srgrimes case 'S': 3921553Srgrimes cp = line+1; 3931553Srgrimes i = 0; 3941553Srgrimes while (*cp >= '0' && *cp <= '9') 3951553Srgrimes i = i * 10 + (*cp++ - '0'); 3961553Srgrimes fdev = i; 3971553Srgrimes cp++; 3981553Srgrimes i = 0; 3991553Srgrimes while (*cp >= '0' && *cp <= '9') 4001553Srgrimes i = i * 10 + (*cp++ - '0'); 4011553Srgrimes fino = i; 4021553Srgrimes continue; 4031553Srgrimes 4041553Srgrimes case 'J': 4051553Srgrimes if (line[1] != '\0') 4061553Srgrimes strncpy(jobname, line+1, sizeof(jobname)-1); 4071553Srgrimes else 4081553Srgrimes strcpy(jobname, " "); 4091553Srgrimes continue; 4101553Srgrimes 4111553Srgrimes case 'C': 4121553Srgrimes if (line[1] != '\0') 4131553Srgrimes strncpy(class, line+1, sizeof(class)-1); 4141553Srgrimes else if (class[0] == '\0') 4151553Srgrimes gethostname(class, sizeof(class)); 4161553Srgrimes continue; 4171553Srgrimes 4181553Srgrimes case 'T': /* header title for pr */ 4191553Srgrimes strncpy(title, line+1, sizeof(title)-1); 4201553Srgrimes continue; 4211553Srgrimes 4221553Srgrimes case 'L': /* identification line */ 4231553Srgrimes if (!SH && !HL) 4241553Srgrimes banner(line+1, jobname); 4251553Srgrimes continue; 4261553Srgrimes 4271553Srgrimes case '1': /* troff fonts */ 4281553Srgrimes case '2': 4291553Srgrimes case '3': 4301553Srgrimes case '4': 4311553Srgrimes if (line[1] != '\0') 4321553Srgrimes strcpy(fonts[line[0]-'1'], line+1); 4331553Srgrimes continue; 4341553Srgrimes 4351553Srgrimes case 'W': /* page width */ 4361553Srgrimes strncpy(width+2, line+1, sizeof(width)-3); 4371553Srgrimes continue; 4381553Srgrimes 4391553Srgrimes case 'I': /* indent amount */ 4401553Srgrimes strncpy(indent+2, line+1, sizeof(indent)-3); 4411553Srgrimes continue; 4421553Srgrimes 4431553Srgrimes default: /* some file to print */ 4441553Srgrimes switch (i = print(line[0], line+1)) { 4451553Srgrimes case ERROR: 4461553Srgrimes if (bombed == OK) 4471553Srgrimes bombed = FATALERR; 4481553Srgrimes break; 4491553Srgrimes case REPRINT: 4501553Srgrimes (void) fclose(cfp); 4511553Srgrimes return(REPRINT); 4521553Srgrimes case FILTERERR: 4531553Srgrimes case ACCESS: 4541553Srgrimes bombed = i; 4551553Srgrimes sendmail(logname, bombed); 4561553Srgrimes } 4571553Srgrimes title[0] = '\0'; 4581553Srgrimes continue; 4591553Srgrimes 4601553Srgrimes case 'N': 4611553Srgrimes case 'U': 4621553Srgrimes case 'M': 46315648Sjoerg case 'R': 4641553Srgrimes continue; 4651553Srgrimes } 4661553Srgrimes 4671553Srgrimes /* pass 2 */ 4681553Srgrimes 4691553Srgrimespass2: 4701553Srgrimes fseek(cfp, 0L, 0); 4711553Srgrimes while (getline(cfp)) 4721553Srgrimes switch (line[0]) { 4731553Srgrimes case 'L': /* identification line */ 4741553Srgrimes if (!SH && HL) 4751553Srgrimes banner(line+1, jobname); 4761553Srgrimes continue; 4771553Srgrimes 4781553Srgrimes case 'M': 4791553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 4801553Srgrimes sendmail(line+1, bombed); 4811553Srgrimes continue; 4821553Srgrimes 4831553Srgrimes case 'U': 4841553Srgrimes (void) unlink(line+1); 4851553Srgrimes } 4861553Srgrimes /* 4871553Srgrimes * clean-up in case another control file exists 4881553Srgrimes */ 4891553Srgrimes (void) fclose(cfp); 4901553Srgrimes (void) unlink(file); 4911553Srgrimes return(bombed == OK ? OK : ERROR); 4921553Srgrimes} 4931553Srgrimes 4941553Srgrimes/* 4951553Srgrimes * Print a file. 4961553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 4971553Srgrimes * Return -1 if a non-recoverable error occured, 4981553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 4991553Srgrimes * 1 if we should try to reprint this job and 5001553Srgrimes * 0 if all is well. 5011553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5021553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5031553Srgrimes */ 5041553Srgrimesstatic int 5051553Srgrimesprint(format, file) 5061553Srgrimes int format; 5071553Srgrimes char *file; 5081553Srgrimes{ 5091553Srgrimes register int n; 5101553Srgrimes register char *prog; 5111553Srgrimes int fi, fo; 5121553Srgrimes FILE *fp; 5131553Srgrimes char *av[15], buf[BUFSIZ]; 5141553Srgrimes int pid, p[2], stopped = 0; 5151553Srgrimes union wait status; 5161553Srgrimes struct stat stb; 5171553Srgrimes 5181553Srgrimes if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 5191553Srgrimes return(ERROR); 5201553Srgrimes /* 5211553Srgrimes * Check to see if data file is a symbolic link. If so, it should 5221553Srgrimes * still point to the same file or someone is trying to print 5231553Srgrimes * something he shouldn't. 5241553Srgrimes */ 5251553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 5261553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 5271553Srgrimes return(ACCESS); 5281553Srgrimes if (!SF && !tof) { /* start on a fresh page */ 5291553Srgrimes (void) write(ofd, FF, strlen(FF)); 5301553Srgrimes tof = 1; 5311553Srgrimes } 5321553Srgrimes if (IF == NULL && (format == 'f' || format == 'l')) { 5331553Srgrimes tof = 0; 5341553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 5351553Srgrimes if (write(ofd, buf, n) != n) { 5361553Srgrimes (void) close(fi); 5371553Srgrimes return(REPRINT); 5381553Srgrimes } 5391553Srgrimes (void) close(fi); 5401553Srgrimes return(OK); 5411553Srgrimes } 5421553Srgrimes switch (format) { 5431553Srgrimes case 'p': /* print file using 'pr' */ 5441553Srgrimes if (IF == NULL) { /* use output filter */ 5451553Srgrimes prog = _PATH_PR; 5461553Srgrimes av[0] = "pr"; 5471553Srgrimes av[1] = width; 5481553Srgrimes av[2] = length; 5491553Srgrimes av[3] = "-h"; 5501553Srgrimes av[4] = *title ? title : " "; 5515445Sjoerg av[5] = "-F"; 5525445Sjoerg av[6] = 0; 5531553Srgrimes fo = ofd; 5541553Srgrimes goto start; 5551553Srgrimes } 5561553Srgrimes pipe(p); 5571553Srgrimes if ((prchild = dofork(DORETURN)) == 0) { /* child */ 5581553Srgrimes dup2(fi, 0); /* file is stdin */ 5591553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 5608094Sjkh closelog(); 5611553Srgrimes for (n = 3; n < NOFILE; n++) 5621553Srgrimes (void) close(n); 5631553Srgrimes execl(_PATH_PR, "pr", width, length, 5645445Sjoerg "-h", *title ? title : " ", "-F", 0); 5651553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 5661553Srgrimes exit(2); 5671553Srgrimes } 5681553Srgrimes (void) close(p[1]); /* close output side */ 5691553Srgrimes (void) close(fi); 5701553Srgrimes if (prchild < 0) { 5711553Srgrimes prchild = 0; 5721553Srgrimes (void) close(p[0]); 5731553Srgrimes return(ERROR); 5741553Srgrimes } 5751553Srgrimes fi = p[0]; /* use pipe for input */ 5761553Srgrimes case 'f': /* print plain text file */ 5771553Srgrimes prog = IF; 5781553Srgrimes av[1] = width; 5791553Srgrimes av[2] = length; 5801553Srgrimes av[3] = indent; 5811553Srgrimes n = 4; 5821553Srgrimes break; 5831553Srgrimes case 'l': /* like 'f' but pass control characters */ 5841553Srgrimes prog = IF; 5851553Srgrimes av[1] = "-c"; 5861553Srgrimes av[2] = width; 5871553Srgrimes av[3] = length; 5881553Srgrimes av[4] = indent; 5891553Srgrimes n = 5; 5901553Srgrimes break; 5911553Srgrimes case 'r': /* print a fortran text file */ 5921553Srgrimes prog = RF; 5931553Srgrimes av[1] = width; 5941553Srgrimes av[2] = length; 5951553Srgrimes n = 3; 5961553Srgrimes break; 5971553Srgrimes case 't': /* print troff output */ 5981553Srgrimes case 'n': /* print ditroff output */ 5991553Srgrimes case 'd': /* print tex output */ 6001553Srgrimes (void) unlink(".railmag"); 6011553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 6021553Srgrimes syslog(LOG_ERR, "%s: cannot create .railmag", printer); 6031553Srgrimes (void) unlink(".railmag"); 6041553Srgrimes } else { 6051553Srgrimes for (n = 0; n < 4; n++) { 6061553Srgrimes if (fonts[n][0] != '/') 6071553Srgrimes (void) write(fo, _PATH_VFONT, 6081553Srgrimes sizeof(_PATH_VFONT) - 1); 6091553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 6101553Srgrimes (void) write(fo, "\n", 1); 6111553Srgrimes } 6121553Srgrimes (void) close(fo); 6131553Srgrimes } 6141553Srgrimes prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 6151553Srgrimes av[1] = pxwidth; 6161553Srgrimes av[2] = pxlength; 6171553Srgrimes n = 3; 6181553Srgrimes break; 6191553Srgrimes case 'c': /* print cifplot output */ 6201553Srgrimes prog = CF; 6211553Srgrimes av[1] = pxwidth; 6221553Srgrimes av[2] = pxlength; 6231553Srgrimes n = 3; 6241553Srgrimes break; 6251553Srgrimes case 'g': /* print plot(1G) output */ 6261553Srgrimes prog = GF; 6271553Srgrimes av[1] = pxwidth; 6281553Srgrimes av[2] = pxlength; 6291553Srgrimes n = 3; 6301553Srgrimes break; 6311553Srgrimes case 'v': /* print raster output */ 6321553Srgrimes prog = VF; 6331553Srgrimes av[1] = pxwidth; 6341553Srgrimes av[2] = pxlength; 6351553Srgrimes n = 3; 6361553Srgrimes break; 6371553Srgrimes default: 6381553Srgrimes (void) close(fi); 6391553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 6401553Srgrimes printer, format); 6411553Srgrimes return(ERROR); 6421553Srgrimes } 64315648Sjoerg if (prog == NULL) { 64415648Sjoerg (void) close(fi); 64515648Sjoerg syslog(LOG_ERR, 64615648Sjoerg "%s: no filter found in printcap for format character '%c'", 64715648Sjoerg printer, format); 64815648Sjoerg return(ERROR); 64915648Sjoerg } 6501553Srgrimes if ((av[0] = rindex(prog, '/')) != NULL) 6511553Srgrimes av[0]++; 6521553Srgrimes else 6531553Srgrimes av[0] = prog; 6541553Srgrimes av[n++] = "-n"; 6551553Srgrimes av[n++] = logname; 6561553Srgrimes av[n++] = "-h"; 6571553Srgrimes av[n++] = fromhost; 6581553Srgrimes av[n++] = AF; 6591553Srgrimes av[n] = 0; 6601553Srgrimes fo = pfd; 6611553Srgrimes if (ofilter > 0) { /* stop output filter */ 6621553Srgrimes write(ofd, "\031\1", 2); 6631553Srgrimes while ((pid = 6641553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 6651553Srgrimes ; 6661553Srgrimes if (status.w_stopval != WSTOPPED) { 6671553Srgrimes (void) close(fi); 66815648Sjoerg syslog(LOG_WARNING, 66915648Sjoerg "%s: output filter died (retcode=%d termsig=%d)", 67015648Sjoerg printer, status.w_retcode, status.w_termsig); 6711553Srgrimes return(REPRINT); 6721553Srgrimes } 6731553Srgrimes stopped++; 6741553Srgrimes } 6751553Srgrimesstart: 6761553Srgrimes if ((child = dofork(DORETURN)) == 0) { /* child */ 6771553Srgrimes dup2(fi, 0); 6781553Srgrimes dup2(fo, 1); 6791553Srgrimes n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 6801553Srgrimes if (n >= 0) 6811553Srgrimes dup2(n, 2); 6828094Sjkh closelog(); 6831553Srgrimes for (n = 3; n < NOFILE; n++) 6841553Srgrimes (void) close(n); 6851553Srgrimes execv(prog, av); 6861553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 6871553Srgrimes exit(2); 6881553Srgrimes } 6891553Srgrimes (void) close(fi); 6901553Srgrimes if (child < 0) 6911553Srgrimes status.w_retcode = 100; 6921553Srgrimes else 6931553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 6941553Srgrimes ; 6951553Srgrimes child = 0; 6961553Srgrimes prchild = 0; 6971553Srgrimes if (stopped) { /* restart output filter */ 6981553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 6991553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 7001553Srgrimes exit(1); 7011553Srgrimes } 7021553Srgrimes } 7031553Srgrimes tof = 0; 7041553Srgrimes 7051553Srgrimes /* Copy filter output to "lf" logfile */ 7061553Srgrimes if (fp = fopen(tempfile, "r")) { 7071553Srgrimes while (fgets(buf, sizeof(buf), fp)) 7081553Srgrimes fputs(buf, stderr); 7091553Srgrimes fclose(fp); 7101553Srgrimes } 7111553Srgrimes 7121553Srgrimes if (!WIFEXITED(status)) { 71315648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 7141553Srgrimes printer, format, status.w_termsig); 7151553Srgrimes return(ERROR); 7161553Srgrimes } 7171553Srgrimes switch (status.w_retcode) { 7181553Srgrimes case 0: 7191553Srgrimes tof = 1; 7201553Srgrimes return(OK); 7211553Srgrimes case 1: 7221553Srgrimes return(REPRINT); 72315648Sjoerg case 2: 72415648Sjoerg return(ERROR); 7251553Srgrimes default: 72615648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 7271553Srgrimes printer, format, status.w_retcode); 72815648Sjoerg return(FILTERERR); 7291553Srgrimes } 7301553Srgrimes} 7311553Srgrimes 7321553Srgrimes/* 7331553Srgrimes * Send the daemon control file (cf) and any data files. 7341553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 7351553Srgrimes * 0 if all is well. 7361553Srgrimes */ 7371553Srgrimesstatic int 7381553Srgrimessendit(file) 7391553Srgrimes char *file; 7401553Srgrimes{ 7411553Srgrimes register int i, err = OK; 7421553Srgrimes char *cp, last[BUFSIZ]; 7431553Srgrimes 7441553Srgrimes /* 7451553Srgrimes * open control file 7461553Srgrimes */ 7471553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 7481553Srgrimes return(OK); 7491553Srgrimes /* 7501553Srgrimes * read the control file for work to do 7511553Srgrimes * 7521553Srgrimes * file format -- first character in the line is a command 7531553Srgrimes * rest of the line is the argument. 7541553Srgrimes * commands of interest are: 7551553Srgrimes * 7561553Srgrimes * a-z -- "file name" name of file to print 7571553Srgrimes * U -- "unlink" name of file to remove 7581553Srgrimes * (after we print it. (Pass 2 only)). 7591553Srgrimes */ 7601553Srgrimes 7611553Srgrimes /* 7621553Srgrimes * pass 1 7631553Srgrimes */ 7641553Srgrimes while (getline(cfp)) { 7651553Srgrimes again: 7661553Srgrimes if (line[0] == 'S') { 7671553Srgrimes cp = line+1; 7681553Srgrimes i = 0; 7691553Srgrimes while (*cp >= '0' && *cp <= '9') 7701553Srgrimes i = i * 10 + (*cp++ - '0'); 7711553Srgrimes fdev = i; 7721553Srgrimes cp++; 7731553Srgrimes i = 0; 7741553Srgrimes while (*cp >= '0' && *cp <= '9') 7751553Srgrimes i = i * 10 + (*cp++ - '0'); 7761553Srgrimes fino = i; 7771553Srgrimes continue; 7781553Srgrimes } 7791553Srgrimes if (line[0] >= 'a' && line[0] <= 'z') { 7801553Srgrimes strcpy(last, line); 7811553Srgrimes while (i = getline(cfp)) 7821553Srgrimes if (strcmp(last, line)) 7831553Srgrimes break; 7841553Srgrimes switch (sendfile('\3', last+1)) { 7851553Srgrimes case OK: 7861553Srgrimes if (i) 7871553Srgrimes goto again; 7881553Srgrimes break; 7891553Srgrimes case REPRINT: 7901553Srgrimes (void) fclose(cfp); 7911553Srgrimes return(REPRINT); 7921553Srgrimes case ACCESS: 7931553Srgrimes sendmail(logname, ACCESS); 7941553Srgrimes case ERROR: 7951553Srgrimes err = ERROR; 7961553Srgrimes } 7971553Srgrimes break; 7981553Srgrimes } 7991553Srgrimes } 8001553Srgrimes if (err == OK && sendfile('\2', file) > 0) { 8011553Srgrimes (void) fclose(cfp); 8021553Srgrimes return(REPRINT); 8031553Srgrimes } 8041553Srgrimes /* 8051553Srgrimes * pass 2 8061553Srgrimes */ 8071553Srgrimes fseek(cfp, 0L, 0); 8081553Srgrimes while (getline(cfp)) 8091553Srgrimes if (line[0] == 'U') 8101553Srgrimes (void) unlink(line+1); 8111553Srgrimes /* 8121553Srgrimes * clean-up in case another control file exists 8131553Srgrimes */ 8141553Srgrimes (void) fclose(cfp); 8151553Srgrimes (void) unlink(file); 8161553Srgrimes return(err); 8171553Srgrimes} 8181553Srgrimes 8191553Srgrimes/* 8201553Srgrimes * Send a data file to the remote machine and spool it. 8211553Srgrimes * Return positive if we should try resending. 8221553Srgrimes */ 8231553Srgrimesstatic int 8241553Srgrimessendfile(type, file) 8251553Srgrimes int type; 8261553Srgrimes char *file; 8271553Srgrimes{ 8281553Srgrimes register int f, i, amt; 8291553Srgrimes struct stat stb; 8301553Srgrimes char buf[BUFSIZ]; 8311553Srgrimes int sizerr, resp; 8321553Srgrimes 8331553Srgrimes if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 8341553Srgrimes return(ERROR); 8351553Srgrimes /* 8361553Srgrimes * Check to see if data file is a symbolic link. If so, it should 8371553Srgrimes * still point to the same file or someone is trying to print something 8381553Srgrimes * he shouldn't. 8391553Srgrimes */ 8401553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 8411553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 8421553Srgrimes return(ACCESS); 8431553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 8441553Srgrimes amt = strlen(buf); 8451553Srgrimes for (i = 0; ; i++) { 8461553Srgrimes if (write(pfd, buf, amt) != amt || 8471553Srgrimes (resp = response()) < 0 || resp == '\1') { 8481553Srgrimes (void) close(f); 8491553Srgrimes return(REPRINT); 8501553Srgrimes } else if (resp == '\0') 8511553Srgrimes break; 8521553Srgrimes if (i == 0) 8531553Srgrimes pstatus("no space on remote; waiting for queue to drain"); 8541553Srgrimes if (i == 10) 8551553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 8561553Srgrimes printer, RM); 8571553Srgrimes sleep(5 * 60); 8581553Srgrimes } 8591553Srgrimes if (i) 8601553Srgrimes pstatus("sending to %s", RM); 8611553Srgrimes sizerr = 0; 8621553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 8631553Srgrimes amt = BUFSIZ; 8641553Srgrimes if (i + amt > stb.st_size) 8651553Srgrimes amt = stb.st_size - i; 8661553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 8671553Srgrimes sizerr = 1; 8681553Srgrimes if (write(pfd, buf, amt) != amt) { 8691553Srgrimes (void) close(f); 8701553Srgrimes return(REPRINT); 8711553Srgrimes } 8721553Srgrimes } 8731553Srgrimes 8741553Srgrimes 8751553Srgrimes 8761553Srgrimes 8771553Srgrimes (void) close(f); 8781553Srgrimes if (sizerr) { 8791553Srgrimes syslog(LOG_INFO, "%s: %s: changed size", printer, file); 8801553Srgrimes /* tell recvjob to ignore this file */ 8811553Srgrimes (void) write(pfd, "\1", 1); 8821553Srgrimes return(ERROR); 8831553Srgrimes } 8841553Srgrimes if (write(pfd, "", 1) != 1 || response()) 8851553Srgrimes return(REPRINT); 8861553Srgrimes return(OK); 8871553Srgrimes} 8881553Srgrimes 8891553Srgrimes/* 8901553Srgrimes * Check to make sure there have been no errors and that both programs 8911553Srgrimes * are in sync with eachother. 8921553Srgrimes * Return non-zero if the connection was lost. 8931553Srgrimes */ 8941553Srgrimesstatic char 8951553Srgrimesresponse() 8961553Srgrimes{ 8971553Srgrimes char resp; 8981553Srgrimes 8991553Srgrimes if (read(pfd, &resp, 1) != 1) { 9001553Srgrimes syslog(LOG_INFO, "%s: lost connection", printer); 9011553Srgrimes return(-1); 9021553Srgrimes } 9031553Srgrimes return(resp); 9041553Srgrimes} 9051553Srgrimes 9061553Srgrimes/* 9071553Srgrimes * Banner printing stuff 9081553Srgrimes */ 9091553Srgrimesstatic void 9101553Srgrimesbanner(name1, name2) 9111553Srgrimes char *name1, *name2; 9121553Srgrimes{ 9131553Srgrimes time_t tvec; 9141553Srgrimes 9151553Srgrimes time(&tvec); 9161553Srgrimes if (!SF && !tof) 9171553Srgrimes (void) write(ofd, FF, strlen(FF)); 9181553Srgrimes if (SB) { /* short banner only */ 9191553Srgrimes if (class[0]) { 9201553Srgrimes (void) write(ofd, class, strlen(class)); 9211553Srgrimes (void) write(ofd, ":", 1); 9221553Srgrimes } 9231553Srgrimes (void) write(ofd, name1, strlen(name1)); 9241553Srgrimes (void) write(ofd, " Job: ", 7); 9251553Srgrimes (void) write(ofd, name2, strlen(name2)); 9261553Srgrimes (void) write(ofd, " Date: ", 8); 9271553Srgrimes (void) write(ofd, ctime(&tvec), 24); 9281553Srgrimes (void) write(ofd, "\n", 1); 9291553Srgrimes } else { /* normal banner */ 9301553Srgrimes (void) write(ofd, "\n\n\n", 3); 9311553Srgrimes scan_out(ofd, name1, '\0'); 9321553Srgrimes (void) write(ofd, "\n\n", 2); 9331553Srgrimes scan_out(ofd, name2, '\0'); 9341553Srgrimes if (class[0]) { 9351553Srgrimes (void) write(ofd,"\n\n\n",3); 9361553Srgrimes scan_out(ofd, class, '\0'); 9371553Srgrimes } 9381553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 9391553Srgrimes (void) write(ofd, name2, strlen(name2)); 9401553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 9411553Srgrimes (void) write(ofd, ctime(&tvec), 24); 9421553Srgrimes (void) write(ofd, "\n", 1); 9431553Srgrimes } 9441553Srgrimes if (!SF) 9451553Srgrimes (void) write(ofd, FF, strlen(FF)); 9461553Srgrimes tof = 1; 9471553Srgrimes} 9481553Srgrimes 9491553Srgrimesstatic char * 9501553Srgrimesscnline(key, p, c) 9511553Srgrimes register int key; 9521553Srgrimes register char *p; 9531553Srgrimes int c; 9541553Srgrimes{ 9551553Srgrimes register scnwidth; 9561553Srgrimes 9571553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 9581553Srgrimes key <<= 1; 9591553Srgrimes *p++ = key & 0200 ? c : BACKGND; 9601553Srgrimes } 9611553Srgrimes return (p); 9621553Srgrimes} 9631553Srgrimes 9641553Srgrimes#define TRC(q) (((q)-' ')&0177) 9651553Srgrimes 9661553Srgrimesstatic void 9671553Srgrimesscan_out(scfd, scsp, dlm) 9681553Srgrimes int scfd, dlm; 9691553Srgrimes char *scsp; 9701553Srgrimes{ 9711553Srgrimes register char *strp; 9721553Srgrimes register nchrs, j; 9731553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 9741553Srgrimes int d, scnhgt; 9751553Srgrimes 9761553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 9771553Srgrimes strp = &outbuf[0]; 9781553Srgrimes sp = scsp; 9791553Srgrimes for (nchrs = 0; ; ) { 9801553Srgrimes d = dropit(c = TRC(cc = *sp++)); 9811553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 9821553Srgrimes for (j = WIDTH; --j;) 9831553Srgrimes *strp++ = BACKGND; 9841553Srgrimes else 9851553Srgrimes strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 9861553Srgrimes if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 9871553Srgrimes break; 9881553Srgrimes *strp++ = BACKGND; 9891553Srgrimes *strp++ = BACKGND; 9901553Srgrimes } 9911553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 9921553Srgrimes ; 9931553Srgrimes strp++; 9948857Srgrimes *strp++ = '\n'; 9951553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 9961553Srgrimes } 9971553Srgrimes} 9981553Srgrimes 9991553Srgrimesstatic int 10001553Srgrimesdropit(c) 10011553Srgrimes int c; 10021553Srgrimes{ 10031553Srgrimes switch(c) { 10041553Srgrimes 10051553Srgrimes case TRC('_'): 10061553Srgrimes case TRC(';'): 10071553Srgrimes case TRC(','): 10081553Srgrimes case TRC('g'): 10091553Srgrimes case TRC('j'): 10101553Srgrimes case TRC('p'): 10111553Srgrimes case TRC('q'): 10121553Srgrimes case TRC('y'): 10131553Srgrimes return (DROP); 10141553Srgrimes 10151553Srgrimes default: 10161553Srgrimes return (0); 10171553Srgrimes } 10181553Srgrimes} 10191553Srgrimes 10201553Srgrimes/* 10211553Srgrimes * sendmail --- 10221553Srgrimes * tell people about job completion 10231553Srgrimes */ 10241553Srgrimesstatic void 10251553Srgrimessendmail(user, bombed) 10261553Srgrimes char *user; 10271553Srgrimes int bombed; 10281553Srgrimes{ 10291553Srgrimes register int i; 10301553Srgrimes int p[2], s; 10311553Srgrimes register char *cp; 10321553Srgrimes char buf[100]; 10331553Srgrimes struct stat stb; 10341553Srgrimes FILE *fp; 10351553Srgrimes 10361553Srgrimes pipe(p); 10371553Srgrimes if ((s = dofork(DORETURN)) == 0) { /* child */ 10381553Srgrimes dup2(p[0], 0); 10398094Sjkh closelog(); 10401553Srgrimes for (i = 3; i < NOFILE; i++) 10411553Srgrimes (void) close(i); 10421553Srgrimes if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 10431553Srgrimes cp++; 10441553Srgrimes else 10451553Srgrimes cp = _PATH_SENDMAIL; 10461553Srgrimes sprintf(buf, "%s@%s", user, fromhost); 10471553Srgrimes execl(_PATH_SENDMAIL, cp, buf, 0); 10481553Srgrimes exit(0); 10491553Srgrimes } else if (s > 0) { /* parent */ 10501553Srgrimes dup2(p[1], 1); 10511553Srgrimes printf("To: %s@%s\n", user, fromhost); 105215648Sjoerg printf("Subject: %s printer job \"%s\"\n", printer, 105315648Sjoerg *jobname ? jobname : "<unknown>"); 105415648Sjoerg printf("Reply-To: root@%s\n\n", host); 10551553Srgrimes printf("Your printer job "); 10561553Srgrimes if (*jobname) 10571553Srgrimes printf("(%s) ", jobname); 10581553Srgrimes switch (bombed) { 10591553Srgrimes case OK: 10601553Srgrimes printf("\ncompleted successfully\n"); 106115648Sjoerg cp = "OK"; 10621553Srgrimes break; 10631553Srgrimes default: 10641553Srgrimes case FATALERR: 10651553Srgrimes printf("\ncould not be printed\n"); 106615648Sjoerg cp = "FATALERR"; 10671553Srgrimes break; 10681553Srgrimes case NOACCT: 10691553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 107015648Sjoerg cp = "NOACCT"; 10711553Srgrimes break; 10721553Srgrimes case FILTERERR: 10731553Srgrimes if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 10741553Srgrimes (fp = fopen(tempfile, "r")) == NULL) { 107515648Sjoerg printf("\nhad some errors and may not have printed\n"); 10761553Srgrimes break; 10771553Srgrimes } 107815648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 10791553Srgrimes while ((i = getc(fp)) != EOF) 10801553Srgrimes putchar(i); 10811553Srgrimes (void) fclose(fp); 108215648Sjoerg cp = "FILTERERR"; 10831553Srgrimes break; 10841553Srgrimes case ACCESS: 10851553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 108615648Sjoerg cp = "ACCESS"; 10871553Srgrimes } 10881553Srgrimes fflush(stdout); 10891553Srgrimes (void) close(1); 10901553Srgrimes } 10911553Srgrimes (void) close(p[0]); 10921553Srgrimes (void) close(p[1]); 109315648Sjoerg wait(NULL); 109415648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 109515648Sjoerg user, *jobname ? jobname : "<unknown>", printer, cp); 10961553Srgrimes} 10971553Srgrimes 10981553Srgrimes/* 10991553Srgrimes * dofork - fork with retries on failure 11001553Srgrimes */ 11011553Srgrimesstatic int 11021553Srgrimesdofork(action) 11031553Srgrimes int action; 11041553Srgrimes{ 11051553Srgrimes register int i, pid; 11061553Srgrimes 11071553Srgrimes for (i = 0; i < 20; i++) { 11081553Srgrimes if ((pid = fork()) < 0) { 11091553Srgrimes sleep((unsigned)(i*i)); 11101553Srgrimes continue; 11111553Srgrimes } 11121553Srgrimes /* 11131553Srgrimes * Child should run as daemon instead of root 11141553Srgrimes */ 111515648Sjoerg if (pid == 0) 11161553Srgrimes setuid(DU); 11171553Srgrimes return(pid); 11181553Srgrimes } 11191553Srgrimes syslog(LOG_ERR, "can't fork"); 11201553Srgrimes 11211553Srgrimes switch (action) { 11221553Srgrimes case DORETURN: 11231553Srgrimes return (-1); 11241553Srgrimes default: 11251553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 11261553Srgrimes /*FALL THRU*/ 11271553Srgrimes case DOABORT: 11281553Srgrimes exit(1); 11291553Srgrimes } 11301553Srgrimes /*NOTREACHED*/ 11311553Srgrimes} 11321553Srgrimes 11331553Srgrimes/* 11341553Srgrimes * Kill child processes to abort current job. 11351553Srgrimes */ 11361553Srgrimesstatic void 11371553Srgrimesabortpr(signo) 11381553Srgrimes int signo; 11391553Srgrimes{ 11401553Srgrimes (void) unlink(tempfile); 11411553Srgrimes kill(0, SIGINT); 11421553Srgrimes if (ofilter > 0) 11431553Srgrimes kill(ofilter, SIGCONT); 11441553Srgrimes while (wait(NULL) > 0) 11451553Srgrimes ; 11461553Srgrimes exit(0); 11471553Srgrimes} 11481553Srgrimes 11491553Srgrimesstatic void 11501553Srgrimesinit() 11511553Srgrimes{ 11521553Srgrimes int status; 11531553Srgrimes char *s; 11541553Srgrimes 11551553Srgrimes if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 11561553Srgrimes syslog(LOG_ERR, "can't open printer description file"); 11571553Srgrimes exit(1); 11581553Srgrimes } else if (status == -1) { 11591553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 11601553Srgrimes exit(1); 11611553Srgrimes } else if (status == -3) 11621553Srgrimes fatal("potential reference loop detected in printcap file"); 11631553Srgrimes 11641553Srgrimes if (cgetstr(bp, "lp", &LP) == -1) 11651553Srgrimes LP = _PATH_DEFDEVLP; 11661553Srgrimes if (cgetstr(bp, "rp", &RP) == -1) 11671553Srgrimes RP = DEFLP; 11681553Srgrimes if (cgetstr(bp, "lo", &LO) == -1) 11691553Srgrimes LO = DEFLOCK; 11701553Srgrimes if (cgetstr(bp, "st", &ST) == -1) 11711553Srgrimes ST = DEFSTAT; 11721553Srgrimes if (cgetstr(bp, "lf", &LF) == -1) 11731553Srgrimes LF = _PATH_CONSOLE; 11741553Srgrimes if (cgetstr(bp, "sd", &SD) == -1) 11751553Srgrimes SD = _PATH_DEFSPOOL; 11761553Srgrimes if (cgetnum(bp, "du", &DU) < 0) 11771553Srgrimes DU = DEFUID; 11781553Srgrimes if (cgetstr(bp,"ff", &FF) == -1) 11791553Srgrimes FF = DEFFF; 11801553Srgrimes if (cgetnum(bp, "pw", &PW) < 0) 11811553Srgrimes PW = DEFWIDTH; 11821553Srgrimes sprintf(&width[2], "%d", PW); 11831553Srgrimes if (cgetnum(bp, "pl", &PL) < 0) 11841553Srgrimes PL = DEFLENGTH; 11851553Srgrimes sprintf(&length[2], "%d", PL); 11861553Srgrimes if (cgetnum(bp,"px", &PX) < 0) 11871553Srgrimes PX = 0; 11881553Srgrimes sprintf(&pxwidth[2], "%d", PX); 11891553Srgrimes if (cgetnum(bp, "py", &PY) < 0) 11901553Srgrimes PY = 0; 11911553Srgrimes sprintf(&pxlength[2], "%d", PY); 11921553Srgrimes cgetstr(bp, "rm", &RM); 11931553Srgrimes if (s = checkremote()) 11941553Srgrimes syslog(LOG_WARNING, s); 11951553Srgrimes 11961553Srgrimes cgetstr(bp, "af", &AF); 11971553Srgrimes cgetstr(bp, "of", &OF); 11981553Srgrimes cgetstr(bp, "if", &IF); 11991553Srgrimes cgetstr(bp, "rf", &RF); 12001553Srgrimes cgetstr(bp, "tf", &TF); 12011553Srgrimes cgetstr(bp, "nf", &NF); 12021553Srgrimes cgetstr(bp, "df", &DF); 12031553Srgrimes cgetstr(bp, "gf", &GF); 12041553Srgrimes cgetstr(bp, "vf", &VF); 12051553Srgrimes cgetstr(bp, "cf", &CF); 12061553Srgrimes cgetstr(bp, "tr", &TR); 120715032Ssef cgetstr(bp, "ms", &MS); 12081553Srgrimes 12091553Srgrimes RS = (cgetcap(bp, "rs", ':') != NULL); 12101553Srgrimes SF = (cgetcap(bp, "sf", ':') != NULL); 12111553Srgrimes SH = (cgetcap(bp, "sh", ':') != NULL); 12121553Srgrimes SB = (cgetcap(bp, "sb", ':') != NULL); 12131553Srgrimes HL = (cgetcap(bp, "hl", ':') != NULL); 12141553Srgrimes RW = (cgetcap(bp, "rw", ':') != NULL); 12151553Srgrimes 12161553Srgrimes cgetnum(bp, "br", &BR); 12171553Srgrimes 12181553Srgrimes tof = (cgetcap(bp, "fo", ':') == NULL); 12191553Srgrimes} 12201553Srgrimes 12211553Srgrimes/* 12221553Srgrimes * Acquire line printer or remote connection. 12231553Srgrimes */ 12241553Srgrimesstatic void 12251553Srgrimesopenpr() 12261553Srgrimes{ 122715648Sjoerg register int i; 122815648Sjoerg char *cp; 12291553Srgrimes 123015648Sjoerg if (!remote && *LP) { 123115648Sjoerg if (cp = index(LP, '@')) 123215648Sjoerg opennet(cp); 123315648Sjoerg else 123415648Sjoerg opentty(); 123515648Sjoerg } else if (remote) { 123615648Sjoerg openrem(); 12371553Srgrimes } else { 12381553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 12391553Srgrimes printer); 12401553Srgrimes exit(1); 12411553Srgrimes } 124215648Sjoerg 12431553Srgrimes /* 12441553Srgrimes * Start up an output filter, if needed. 12451553Srgrimes */ 12461553Srgrimes if (!remote && OF) { 12471553Srgrimes int p[2]; 12481553Srgrimes 12491553Srgrimes pipe(p); 12501553Srgrimes if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 12511553Srgrimes dup2(p[0], 0); /* pipe is std in */ 12521553Srgrimes dup2(pfd, 1); /* printer is std out */ 12538094Sjkh closelog(); 12541553Srgrimes for (i = 3; i < NOFILE; i++) 12551553Srgrimes (void) close(i); 12561553Srgrimes if ((cp = rindex(OF, '/')) == NULL) 12571553Srgrimes cp = OF; 12581553Srgrimes else 12591553Srgrimes cp++; 12601553Srgrimes execl(OF, cp, width, length, 0); 12611553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, OF); 12621553Srgrimes exit(1); 12631553Srgrimes } 12641553Srgrimes (void) close(p[0]); /* close input side */ 12651553Srgrimes ofd = p[1]; /* use pipe for output */ 12661553Srgrimes } else { 12671553Srgrimes ofd = pfd; 12681553Srgrimes ofilter = 0; 12691553Srgrimes } 12701553Srgrimes} 12711553Srgrimes 127215648Sjoerg/* 127315648Sjoerg * Printer connected directly to the network 127415648Sjoerg * or to a terminal server on the net 127515648Sjoerg */ 127615648Sjoergstatic void 127715648Sjoergopennet(cp) 127815648Sjoerg char *cp; 127915648Sjoerg{ 128015648Sjoerg register int i; 128115648Sjoerg int resp, port; 128215648Sjoerg char save_ch; 128315648Sjoerg 128415648Sjoerg save_ch = *cp; 128515648Sjoerg *cp = '\0'; 128615648Sjoerg port = atoi(LP); 128715648Sjoerg if (port <= 0) { 128815648Sjoerg syslog(LOG_ERR, "%s: bad port number: %s", printer, LP); 128915648Sjoerg exit(1); 129015648Sjoerg } 129115648Sjoerg *cp++ = save_ch; 129215648Sjoerg 129315648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 129415648Sjoerg resp = -1; 129515648Sjoerg pfd = getport(cp, port); 129615648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 129715648Sjoerg resp = 1; 129815648Sjoerg else if (pfd >= 0) { 129915648Sjoerg /* 130015648Sjoerg * need to delay a bit for rs232 lines 130115648Sjoerg * to stabilize in case printer is 130215648Sjoerg * connected via a terminal server 130315648Sjoerg */ 130415648Sjoerg delay(500); 130515648Sjoerg break; 130615648Sjoerg } 130715648Sjoerg if (i == 1) { 130815648Sjoerg if (resp < 0) 130915648Sjoerg pstatus("waiting for %s to come up", LP); 131015648Sjoerg else 131115648Sjoerg pstatus("waiting for access to printer on %s", LP); 131215648Sjoerg } 131315648Sjoerg sleep(i); 131415648Sjoerg } 131515648Sjoerg pstatus("sending to %s port %d", cp, port); 131615648Sjoerg} 131715648Sjoerg 131815648Sjoerg/* 131915648Sjoerg * Printer is connected to an RS232 port on this host 132015648Sjoerg */ 132115648Sjoergstatic void 132215648Sjoergopentty() 132315648Sjoerg{ 132415648Sjoerg register int i; 132515648Sjoerg int resp, port; 132615648Sjoerg 132715648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 132815648Sjoerg pfd = open(LP, RW ? O_RDWR : O_WRONLY); 132915648Sjoerg if (pfd >= 0) { 133015648Sjoerg delay(500); 133115648Sjoerg break; 133215648Sjoerg } 133315648Sjoerg if (errno == ENOENT) { 133415648Sjoerg syslog(LOG_ERR, "%s: %m", LP); 133515648Sjoerg exit(1); 133615648Sjoerg } 133715648Sjoerg if (i == 1) 133815648Sjoerg pstatus("waiting for %s to become ready (offline ?)", 133915648Sjoerg printer); 134015648Sjoerg sleep(i); 134115648Sjoerg } 134215648Sjoerg if (isatty(pfd)) 134315648Sjoerg setty(); 134415648Sjoerg pstatus("%s is ready and printing", printer); 134515648Sjoerg} 134615648Sjoerg 134715648Sjoerg/* 134815648Sjoerg * Printer is on a remote host 134915648Sjoerg */ 135015648Sjoergstatic void 135115648Sjoergopenrem() 135215648Sjoerg{ 135315648Sjoerg register int i, n; 135415648Sjoerg int resp, port; 135515648Sjoerg 135615648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 135715648Sjoerg resp = -1; 135815648Sjoerg pfd = getport(RM, 0); 135915648Sjoerg if (pfd >= 0) { 136015648Sjoerg (void) sprintf(line, "\2%s\n", RP); 136115648Sjoerg n = strlen(line); 136215648Sjoerg if (write(pfd, line, n) == n && 136315648Sjoerg (resp = response()) == '\0') 136415648Sjoerg break; 136515648Sjoerg (void) close(pfd); 136615648Sjoerg } 136715648Sjoerg if (i == 1) { 136815648Sjoerg if (resp < 0) 136915648Sjoerg pstatus("waiting for %s to come up", RM); 137015648Sjoerg else { 137115648Sjoerg pstatus("waiting for queue to be enabled on %s", 137215648Sjoerg RM); 137315648Sjoerg i = 256; 137415648Sjoerg } 137515648Sjoerg } 137615648Sjoerg sleep(i); 137715648Sjoerg } 137815648Sjoerg pstatus("sending to %s", RM); 137915648Sjoerg} 138015648Sjoerg 13811553Srgrimesstruct bauds { 13821553Srgrimes int baud; 13831553Srgrimes int speed; 13841553Srgrimes} bauds[] = { 13851553Srgrimes 50, B50, 13861553Srgrimes 75, B75, 13871553Srgrimes 110, B110, 13881553Srgrimes 134, B134, 13891553Srgrimes 150, B150, 13901553Srgrimes 200, B200, 13911553Srgrimes 300, B300, 13921553Srgrimes 600, B600, 13931553Srgrimes 1200, B1200, 13941553Srgrimes 1800, B1800, 13951553Srgrimes 2400, B2400, 13961553Srgrimes 4800, B4800, 13971553Srgrimes 9600, B9600, 13981553Srgrimes 19200, EXTA, 13991553Srgrimes 38400, EXTB, 14009821Swpaul 57600, B57600, 14019821Swpaul 115200, B115200, 14021553Srgrimes 0, 0 14031553Srgrimes}; 14041553Srgrimes 14051553Srgrimes/* 14061553Srgrimes * setup tty lines. 14071553Srgrimes */ 14081553Srgrimesstatic void 14091553Srgrimessetty() 14101553Srgrimes{ 141115032Ssef struct termios ttybuf; 141215032Ssef struct bauds *bp; 14131553Srgrimes 14141553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 14151553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 14161553Srgrimes exit(1); 14171553Srgrimes } 141815032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 141915032Ssef syslog(LOG_ERR, "%s: tcgetattr: %m", printer); 14201553Srgrimes exit(1); 14211553Srgrimes } 14221553Srgrimes if (BR > 0) { 14231553Srgrimes for (bp = bauds; bp->baud; bp++) 14241553Srgrimes if (BR == bp->baud) 14251553Srgrimes break; 14261553Srgrimes if (!bp->baud) { 14271553Srgrimes syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 14281553Srgrimes exit(1); 14291553Srgrimes } 143015032Ssef cfsetspeed(&ttybuf, bp->speed); 14311553Srgrimes } 143215032Ssef if (MS) { 143315032Ssef char *s = strdup(MS), *tmp; 143415032Ssef 143515032Ssef while (tmp = strsep (&s, ",")) { 143615032Ssef msearch(tmp, &ttybuf); 14371553Srgrimes } 14381553Srgrimes } 143915032Ssef if (MS || (BR > 0)) { 144015032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 144115032Ssef syslog(LOG_ERR, "%s: tcsetattr: %m", printer); 14421553Srgrimes } 14431553Srgrimes } 14441553Srgrimes} 14451553Srgrimes 14461553Srgrimes#if __STDC__ 14471553Srgrimes#include <stdarg.h> 14481553Srgrimes#else 14491553Srgrimes#include <varargs.h> 14501553Srgrimes#endif 14511553Srgrimes 145215648Sjoergstatic void 14531553Srgrimes#if __STDC__ 14541553Srgrimespstatus(const char *msg, ...) 14551553Srgrimes#else 14561553Srgrimespstatus(msg, va_alist) 14571553Srgrimes char *msg; 14581553Srgrimes va_dcl 14591553Srgrimes#endif 14601553Srgrimes{ 14611553Srgrimes register int fd; 14621553Srgrimes char buf[BUFSIZ]; 14631553Srgrimes va_list ap; 14641553Srgrimes#if __STDC__ 14651553Srgrimes va_start(ap, msg); 14661553Srgrimes#else 14671553Srgrimes va_start(ap); 14681553Srgrimes#endif 14691553Srgrimes 14701553Srgrimes umask(0); 14711553Srgrimes fd = open(ST, O_WRONLY|O_CREAT, 0664); 14721553Srgrimes if (fd < 0 || flock(fd, LOCK_EX) < 0) { 14731553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, ST); 14741553Srgrimes exit(1); 14751553Srgrimes } 14761553Srgrimes ftruncate(fd, 0); 14771553Srgrimes (void)vsnprintf(buf, sizeof(buf), msg, ap); 14781553Srgrimes va_end(ap); 14791553Srgrimes strcat(buf, "\n"); 14801553Srgrimes (void) write(fd, buf, strlen(buf)); 14811553Srgrimes (void) close(fd); 14821553Srgrimes} 1483