printjob.c revision 1553
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 421553Srgrimesstatic char sccsid[] = "@(#)printjob.c 8.2 (Berkeley) 4/16/94"; 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 <sgtty.h> 621553Srgrimes#include <syslog.h> 631553Srgrimes#include <fcntl.h> 641553Srgrimes#include <dirent.h> 651553Srgrimes#include <errno.h> 661553Srgrimes#include <stdio.h> 671553Srgrimes#include <string.h> 681553Srgrimes#include <stdlib.h> 691553Srgrimes#include "lp.h" 701553Srgrimes#include "lp.local.h" 711553Srgrimes#include "pathnames.h" 721553Srgrimes#include "extern.h" 731553Srgrimes 741553Srgrimes#define DORETURN 0 /* absorb fork error */ 751553Srgrimes#define DOABORT 1 /* abort if dofork fails */ 761553Srgrimes 771553Srgrimes/* 781553Srgrimes * Error tokens 791553Srgrimes */ 801553Srgrimes#define REPRINT -2 811553Srgrimes#define ERROR -1 821553Srgrimes#define OK 0 831553Srgrimes#define FATALERR 1 841553Srgrimes#define NOACCT 2 851553Srgrimes#define FILTERERR 3 861553Srgrimes#define ACCESS 4 871553Srgrimes 881553Srgrimesstatic dev_t fdev; /* device of file pointed to by symlink */ 891553Srgrimesstatic ino_t fino; /* inode of file pointed to by symlink */ 901553Srgrimesstatic FILE *cfp; /* control file */ 911553Srgrimesstatic int child; /* id of any filters */ 921553Srgrimesstatic int lfd; /* lock file descriptor */ 931553Srgrimesstatic int ofd; /* output filter file descriptor */ 941553Srgrimesstatic int ofilter; /* id of output filter, if any */ 951553Srgrimesstatic int pfd; /* prstatic inter file descriptor */ 961553Srgrimesstatic int pid; /* pid of lpd process */ 971553Srgrimesstatic int prchild; /* id of pr process */ 981553Srgrimesstatic int remote; /* true if sending files to remote */ 991553Srgrimesstatic char title[80]; /* ``pr'' title */ 1001553Srgrimesstatic int tof; /* true if at top of form */ 1011553Srgrimes 1021553Srgrimesstatic char class[32]; /* classification field */ 1031553Srgrimesstatic char fromhost[32]; /* user's host machine */ 1041553Srgrimes /* indentation size in static characters */ 1051553Srgrimesstatic char indent[10] = "-i0"; 1061553Srgrimesstatic char jobname[100]; /* job or file name */ 1071553Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1081553Srgrimesstatic char logname[32]; /* user's login name */ 1091553Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1101553Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 1111553Srgrimesstatic char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 1121553Srgrimesstatic char width[10] = "-w"; /* page width in static characters */ 1131553Srgrimes 1141553Srgrimesstatic void abortpr __P((int)); 1151553Srgrimesstatic void banner __P((char *, char *)); 1161553Srgrimesstatic int dofork __P((int)); 1171553Srgrimesstatic int dropit __P((int)); 1181553Srgrimesstatic void init __P((void)); 1191553Srgrimesstatic void openpr __P((void)); 1201553Srgrimesstatic int print __P((int, char *)); 1211553Srgrimesstatic int printit __P((char *)); 1221553Srgrimesstatic void pstatus __P((const char *, ...)); 1231553Srgrimesstatic char response __P((void)); 1241553Srgrimesstatic void scan_out __P((int, char *, int)); 1251553Srgrimesstatic char *scnline __P((int, char *, int)); 1261553Srgrimesstatic int sendfile __P((int, char *)); 1271553Srgrimesstatic int sendit __P((char *)); 1281553Srgrimesstatic void sendmail __P((char *, int)); 1291553Srgrimesstatic void setty __P((void)); 1301553Srgrimes 1311553Srgrimesvoid 1321553Srgrimesprintjob() 1331553Srgrimes{ 1341553Srgrimes struct stat stb; 1351553Srgrimes register struct queue *q, **qp; 1361553Srgrimes struct queue **queue; 1371553Srgrimes register int i, nitems; 1381553Srgrimes long pidoff; 1391553Srgrimes int count = 0; 1401553Srgrimes 1411553Srgrimes init(); /* set up capabilities */ 1421553Srgrimes (void) write(1, "", 1); /* ack that daemon is started */ 1431553Srgrimes (void) close(2); /* set up log file */ 1441553Srgrimes if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 1451553Srgrimes syslog(LOG_ERR, "%s: %m", LF); 1461553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1471553Srgrimes } 1481553Srgrimes setgid(getegid()); 1491553Srgrimes pid = getpid(); /* for use with lprm */ 1501553Srgrimes setpgrp(0, pid); 1511553Srgrimes signal(SIGHUP, abortpr); 1521553Srgrimes signal(SIGINT, abortpr); 1531553Srgrimes signal(SIGQUIT, abortpr); 1541553Srgrimes signal(SIGTERM, abortpr); 1551553Srgrimes 1561553Srgrimes (void) mktemp(tempfile); 1571553Srgrimes 1581553Srgrimes /* 1591553Srgrimes * uses short form file names 1601553Srgrimes */ 1611553Srgrimes if (chdir(SD) < 0) { 1621553Srgrimes syslog(LOG_ERR, "%s: %m", SD); 1631553Srgrimes exit(1); 1641553Srgrimes } 1651553Srgrimes if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 1661553Srgrimes exit(0); /* printing disabled */ 1671553Srgrimes lfd = open(LO, O_WRONLY|O_CREAT, 0644); 1681553Srgrimes if (lfd < 0) { 1691553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1701553Srgrimes exit(1); 1711553Srgrimes } 1721553Srgrimes if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 1731553Srgrimes if (errno == EWOULDBLOCK) /* active deamon present */ 1741553Srgrimes exit(0); 1751553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1761553Srgrimes exit(1); 1771553Srgrimes } 1781553Srgrimes ftruncate(lfd, 0); 1791553Srgrimes /* 1801553Srgrimes * write process id for others to know 1811553Srgrimes */ 1821553Srgrimes sprintf(line, "%u\n", pid); 1831553Srgrimes pidoff = i = strlen(line); 1841553Srgrimes if (write(lfd, line, i) != i) { 1851553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1861553Srgrimes exit(1); 1871553Srgrimes } 1881553Srgrimes /* 1891553Srgrimes * search the spool directory for work and sort by queue order. 1901553Srgrimes */ 1911553Srgrimes if ((nitems = getq(&queue)) < 0) { 1921553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 1931553Srgrimes exit(1); 1941553Srgrimes } 1951553Srgrimes if (nitems == 0) /* no work to do */ 1961553Srgrimes exit(0); 1971553Srgrimes if (stb.st_mode & 01) { /* reset queue flag */ 1981553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 1991553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2001553Srgrimes } 2011553Srgrimes openpr(); /* open printer or remote */ 2021553Srgrimesagain: 2031553Srgrimes /* 2041553Srgrimes * we found something to do now do it -- 2051553Srgrimes * write the name of the current control file into the lock file 2061553Srgrimes * so the spool queue program can tell what we're working on 2071553Srgrimes */ 2081553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2091553Srgrimes q = *qp++; 2101553Srgrimes if (stat(q->q_name, &stb) < 0) 2111553Srgrimes continue; 2121553Srgrimes restart: 2131553Srgrimes (void) lseek(lfd, (off_t)pidoff, 0); 2141553Srgrimes (void) sprintf(line, "%s\n", q->q_name); 2151553Srgrimes i = strlen(line); 2161553Srgrimes if (write(lfd, line, i) != i) 2171553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2181553Srgrimes if (!remote) 2191553Srgrimes i = printit(q->q_name); 2201553Srgrimes else 2211553Srgrimes i = sendit(q->q_name); 2221553Srgrimes /* 2231553Srgrimes * Check to see if we are supposed to stop printing or 2241553Srgrimes * if we are to rebuild the queue. 2251553Srgrimes */ 2261553Srgrimes if (fstat(lfd, &stb) == 0) { 2271553Srgrimes /* stop printing before starting next job? */ 2281553Srgrimes if (stb.st_mode & 0100) 2291553Srgrimes goto done; 2301553Srgrimes /* rebuild queue (after lpc topq) */ 2311553Srgrimes if (stb.st_mode & 01) { 2321553Srgrimes for (free((char *) q); nitems--; free((char *) q)) 2331553Srgrimes q = *qp++; 2341553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2351553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 2361553Srgrimes printer, LO); 2371553Srgrimes break; 2381553Srgrimes } 2391553Srgrimes } 2401553Srgrimes if (i == OK) /* file ok and printed */ 2411553Srgrimes count++; 2421553Srgrimes else if (i == REPRINT) { /* try reprinting the job */ 2431553Srgrimes syslog(LOG_INFO, "restarting %s", printer); 2441553Srgrimes if (ofilter > 0) { 2451553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2461553Srgrimes (void) close(ofd); 2471553Srgrimes while ((i = wait(0)) > 0 && i != ofilter) 2481553Srgrimes ; 2491553Srgrimes ofilter = 0; 2501553Srgrimes } 2511553Srgrimes (void) close(pfd); /* close printer */ 2521553Srgrimes if (ftruncate(lfd, pidoff) < 0) 2531553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 2541553Srgrimes openpr(); /* try to reopen printer */ 2551553Srgrimes goto restart; 2561553Srgrimes } 2571553Srgrimes } 2581553Srgrimes free((char *) queue); 2591553Srgrimes /* 2601553Srgrimes * search the spool directory for more work. 2611553Srgrimes */ 2621553Srgrimes if ((nitems = getq(&queue)) < 0) { 2631553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 2641553Srgrimes exit(1); 2651553Srgrimes } 2661553Srgrimes if (nitems == 0) { /* no more work to do */ 2671553Srgrimes done: 2681553Srgrimes if (count > 0) { /* Files actually printed */ 2691553Srgrimes if (!SF && !tof) 2701553Srgrimes (void) write(ofd, FF, strlen(FF)); 2711553Srgrimes if (TR != NULL) /* output trailer */ 2721553Srgrimes (void) write(ofd, TR, strlen(TR)); 2731553Srgrimes } 2741553Srgrimes (void) unlink(tempfile); 2751553Srgrimes exit(0); 2761553Srgrimes } 2771553Srgrimes goto again; 2781553Srgrimes} 2791553Srgrimes 2801553Srgrimeschar fonts[4][50]; /* fonts for troff */ 2811553Srgrimes 2821553Srgrimeschar ifonts[4][40] = { 2831553Srgrimes _PATH_VFONTR, 2841553Srgrimes _PATH_VFONTI, 2851553Srgrimes _PATH_VFONTB, 2861553Srgrimes _PATH_VFONTS, 2871553Srgrimes}; 2881553Srgrimes 2891553Srgrimes/* 2901553Srgrimes * The remaining part is the reading of the control file (cf) 2911553Srgrimes * and performing the various actions. 2921553Srgrimes */ 2931553Srgrimesstatic int 2941553Srgrimesprintit(file) 2951553Srgrimes char *file; 2961553Srgrimes{ 2971553Srgrimes register int i; 2981553Srgrimes char *cp; 2991553Srgrimes int bombed = OK; 3001553Srgrimes 3011553Srgrimes /* 3021553Srgrimes * open control file; ignore if no longer there. 3031553Srgrimes */ 3041553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 3051553Srgrimes syslog(LOG_INFO, "%s: %s: %m", printer, file); 3061553Srgrimes return(OK); 3071553Srgrimes } 3081553Srgrimes /* 3091553Srgrimes * Reset troff fonts. 3101553Srgrimes */ 3111553Srgrimes for (i = 0; i < 4; i++) 3121553Srgrimes strcpy(fonts[i], ifonts[i]); 3131553Srgrimes sprintf(&width[2], "%d", PW); 3141553Srgrimes strcpy(indent+2, "0"); 3151553Srgrimes 3161553Srgrimes /* 3171553Srgrimes * read the control file for work to do 3181553Srgrimes * 3191553Srgrimes * file format -- first character in the line is a command 3201553Srgrimes * rest of the line is the argument. 3211553Srgrimes * valid commands are: 3221553Srgrimes * 3231553Srgrimes * S -- "stat info" for symbolic link protection 3241553Srgrimes * J -- "job name" on banner page 3251553Srgrimes * C -- "class name" on banner page 3261553Srgrimes * L -- "literal" user's name to print on banner 3271553Srgrimes * T -- "title" for pr 3281553Srgrimes * H -- "host name" of machine where lpr was done 3291553Srgrimes * P -- "person" user's login name 3301553Srgrimes * I -- "indent" amount to indent output 3311553Srgrimes * f -- "file name" name of text file to print 3321553Srgrimes * l -- "file name" text file with control chars 3331553Srgrimes * p -- "file name" text file to print with pr(1) 3341553Srgrimes * t -- "file name" troff(1) file to print 3351553Srgrimes * n -- "file name" ditroff(1) file to print 3361553Srgrimes * d -- "file name" dvi file to print 3371553Srgrimes * g -- "file name" plot(1G) file to print 3381553Srgrimes * v -- "file name" plain raster file to print 3391553Srgrimes * c -- "file name" cifplot file to print 3401553Srgrimes * 1 -- "R font file" for troff 3411553Srgrimes * 2 -- "I font file" for troff 3421553Srgrimes * 3 -- "B font file" for troff 3431553Srgrimes * 4 -- "S font file" for troff 3441553Srgrimes * N -- "name" of file (used by lpq) 3451553Srgrimes * U -- "unlink" name of file to remove 3461553Srgrimes * (after we print it. (Pass 2 only)). 3471553Srgrimes * M -- "mail" to user when done printing 3481553Srgrimes * 3491553Srgrimes * getline reads a line and expands tabs to blanks 3501553Srgrimes */ 3511553Srgrimes 3521553Srgrimes /* pass 1 */ 3531553Srgrimes 3541553Srgrimes while (getline(cfp)) 3551553Srgrimes switch (line[0]) { 3561553Srgrimes case 'H': 3571553Srgrimes strcpy(fromhost, line+1); 3581553Srgrimes if (class[0] == '\0') 3591553Srgrimes strncpy(class, line+1, sizeof(class)-1); 3601553Srgrimes continue; 3611553Srgrimes 3621553Srgrimes case 'P': 3631553Srgrimes strncpy(logname, line+1, sizeof(logname)-1); 3641553Srgrimes if (RS) { /* restricted */ 3651553Srgrimes if (getpwnam(logname) == NULL) { 3661553Srgrimes bombed = NOACCT; 3671553Srgrimes sendmail(line+1, bombed); 3681553Srgrimes goto pass2; 3691553Srgrimes } 3701553Srgrimes } 3711553Srgrimes continue; 3721553Srgrimes 3731553Srgrimes case 'S': 3741553Srgrimes cp = line+1; 3751553Srgrimes i = 0; 3761553Srgrimes while (*cp >= '0' && *cp <= '9') 3771553Srgrimes i = i * 10 + (*cp++ - '0'); 3781553Srgrimes fdev = i; 3791553Srgrimes cp++; 3801553Srgrimes i = 0; 3811553Srgrimes while (*cp >= '0' && *cp <= '9') 3821553Srgrimes i = i * 10 + (*cp++ - '0'); 3831553Srgrimes fino = i; 3841553Srgrimes continue; 3851553Srgrimes 3861553Srgrimes case 'J': 3871553Srgrimes if (line[1] != '\0') 3881553Srgrimes strncpy(jobname, line+1, sizeof(jobname)-1); 3891553Srgrimes else 3901553Srgrimes strcpy(jobname, " "); 3911553Srgrimes continue; 3921553Srgrimes 3931553Srgrimes case 'C': 3941553Srgrimes if (line[1] != '\0') 3951553Srgrimes strncpy(class, line+1, sizeof(class)-1); 3961553Srgrimes else if (class[0] == '\0') 3971553Srgrimes gethostname(class, sizeof(class)); 3981553Srgrimes continue; 3991553Srgrimes 4001553Srgrimes case 'T': /* header title for pr */ 4011553Srgrimes strncpy(title, line+1, sizeof(title)-1); 4021553Srgrimes continue; 4031553Srgrimes 4041553Srgrimes case 'L': /* identification line */ 4051553Srgrimes if (!SH && !HL) 4061553Srgrimes banner(line+1, jobname); 4071553Srgrimes continue; 4081553Srgrimes 4091553Srgrimes case '1': /* troff fonts */ 4101553Srgrimes case '2': 4111553Srgrimes case '3': 4121553Srgrimes case '4': 4131553Srgrimes if (line[1] != '\0') 4141553Srgrimes strcpy(fonts[line[0]-'1'], line+1); 4151553Srgrimes continue; 4161553Srgrimes 4171553Srgrimes case 'W': /* page width */ 4181553Srgrimes strncpy(width+2, line+1, sizeof(width)-3); 4191553Srgrimes continue; 4201553Srgrimes 4211553Srgrimes case 'I': /* indent amount */ 4221553Srgrimes strncpy(indent+2, line+1, sizeof(indent)-3); 4231553Srgrimes continue; 4241553Srgrimes 4251553Srgrimes default: /* some file to print */ 4261553Srgrimes switch (i = print(line[0], line+1)) { 4271553Srgrimes case ERROR: 4281553Srgrimes if (bombed == OK) 4291553Srgrimes bombed = FATALERR; 4301553Srgrimes break; 4311553Srgrimes case REPRINT: 4321553Srgrimes (void) fclose(cfp); 4331553Srgrimes return(REPRINT); 4341553Srgrimes case FILTERERR: 4351553Srgrimes case ACCESS: 4361553Srgrimes bombed = i; 4371553Srgrimes sendmail(logname, bombed); 4381553Srgrimes } 4391553Srgrimes title[0] = '\0'; 4401553Srgrimes continue; 4411553Srgrimes 4421553Srgrimes case 'N': 4431553Srgrimes case 'U': 4441553Srgrimes case 'M': 4451553Srgrimes continue; 4461553Srgrimes } 4471553Srgrimes 4481553Srgrimes /* pass 2 */ 4491553Srgrimes 4501553Srgrimespass2: 4511553Srgrimes fseek(cfp, 0L, 0); 4521553Srgrimes while (getline(cfp)) 4531553Srgrimes switch (line[0]) { 4541553Srgrimes case 'L': /* identification line */ 4551553Srgrimes if (!SH && HL) 4561553Srgrimes banner(line+1, jobname); 4571553Srgrimes continue; 4581553Srgrimes 4591553Srgrimes case 'M': 4601553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 4611553Srgrimes sendmail(line+1, bombed); 4621553Srgrimes continue; 4631553Srgrimes 4641553Srgrimes case 'U': 4651553Srgrimes (void) unlink(line+1); 4661553Srgrimes } 4671553Srgrimes /* 4681553Srgrimes * clean-up in case another control file exists 4691553Srgrimes */ 4701553Srgrimes (void) fclose(cfp); 4711553Srgrimes (void) unlink(file); 4721553Srgrimes return(bombed == OK ? OK : ERROR); 4731553Srgrimes} 4741553Srgrimes 4751553Srgrimes/* 4761553Srgrimes * Print a file. 4771553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 4781553Srgrimes * Return -1 if a non-recoverable error occured, 4791553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 4801553Srgrimes * 1 if we should try to reprint this job and 4811553Srgrimes * 0 if all is well. 4821553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 4831553Srgrimes * stderr as the log file, and must not ignore SIGINT. 4841553Srgrimes */ 4851553Srgrimesstatic int 4861553Srgrimesprint(format, file) 4871553Srgrimes int format; 4881553Srgrimes char *file; 4891553Srgrimes{ 4901553Srgrimes register int n; 4911553Srgrimes register char *prog; 4921553Srgrimes int fi, fo; 4931553Srgrimes FILE *fp; 4941553Srgrimes char *av[15], buf[BUFSIZ]; 4951553Srgrimes int pid, p[2], stopped = 0; 4961553Srgrimes union wait status; 4971553Srgrimes struct stat stb; 4981553Srgrimes 4991553Srgrimes if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 5001553Srgrimes return(ERROR); 5011553Srgrimes /* 5021553Srgrimes * Check to see if data file is a symbolic link. If so, it should 5031553Srgrimes * still point to the same file or someone is trying to print 5041553Srgrimes * something he shouldn't. 5051553Srgrimes */ 5061553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 5071553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 5081553Srgrimes return(ACCESS); 5091553Srgrimes if (!SF && !tof) { /* start on a fresh page */ 5101553Srgrimes (void) write(ofd, FF, strlen(FF)); 5111553Srgrimes tof = 1; 5121553Srgrimes } 5131553Srgrimes if (IF == NULL && (format == 'f' || format == 'l')) { 5141553Srgrimes tof = 0; 5151553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 5161553Srgrimes if (write(ofd, buf, n) != n) { 5171553Srgrimes (void) close(fi); 5181553Srgrimes return(REPRINT); 5191553Srgrimes } 5201553Srgrimes (void) close(fi); 5211553Srgrimes return(OK); 5221553Srgrimes } 5231553Srgrimes switch (format) { 5241553Srgrimes case 'p': /* print file using 'pr' */ 5251553Srgrimes if (IF == NULL) { /* use output filter */ 5261553Srgrimes prog = _PATH_PR; 5271553Srgrimes av[0] = "pr"; 5281553Srgrimes av[1] = width; 5291553Srgrimes av[2] = length; 5301553Srgrimes av[3] = "-h"; 5311553Srgrimes av[4] = *title ? title : " "; 5321553Srgrimes av[5] = 0; 5331553Srgrimes fo = ofd; 5341553Srgrimes goto start; 5351553Srgrimes } 5361553Srgrimes pipe(p); 5371553Srgrimes if ((prchild = dofork(DORETURN)) == 0) { /* child */ 5381553Srgrimes dup2(fi, 0); /* file is stdin */ 5391553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 5401553Srgrimes for (n = 3; n < NOFILE; n++) 5411553Srgrimes (void) close(n); 5421553Srgrimes execl(_PATH_PR, "pr", width, length, 5431553Srgrimes "-h", *title ? title : " ", 0); 5441553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 5451553Srgrimes exit(2); 5461553Srgrimes } 5471553Srgrimes (void) close(p[1]); /* close output side */ 5481553Srgrimes (void) close(fi); 5491553Srgrimes if (prchild < 0) { 5501553Srgrimes prchild = 0; 5511553Srgrimes (void) close(p[0]); 5521553Srgrimes return(ERROR); 5531553Srgrimes } 5541553Srgrimes fi = p[0]; /* use pipe for input */ 5551553Srgrimes case 'f': /* print plain text file */ 5561553Srgrimes prog = IF; 5571553Srgrimes av[1] = width; 5581553Srgrimes av[2] = length; 5591553Srgrimes av[3] = indent; 5601553Srgrimes n = 4; 5611553Srgrimes break; 5621553Srgrimes case 'l': /* like 'f' but pass control characters */ 5631553Srgrimes prog = IF; 5641553Srgrimes av[1] = "-c"; 5651553Srgrimes av[2] = width; 5661553Srgrimes av[3] = length; 5671553Srgrimes av[4] = indent; 5681553Srgrimes n = 5; 5691553Srgrimes break; 5701553Srgrimes case 'r': /* print a fortran text file */ 5711553Srgrimes prog = RF; 5721553Srgrimes av[1] = width; 5731553Srgrimes av[2] = length; 5741553Srgrimes n = 3; 5751553Srgrimes break; 5761553Srgrimes case 't': /* print troff output */ 5771553Srgrimes case 'n': /* print ditroff output */ 5781553Srgrimes case 'd': /* print tex output */ 5791553Srgrimes (void) unlink(".railmag"); 5801553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 5811553Srgrimes syslog(LOG_ERR, "%s: cannot create .railmag", printer); 5821553Srgrimes (void) unlink(".railmag"); 5831553Srgrimes } else { 5841553Srgrimes for (n = 0; n < 4; n++) { 5851553Srgrimes if (fonts[n][0] != '/') 5861553Srgrimes (void) write(fo, _PATH_VFONT, 5871553Srgrimes sizeof(_PATH_VFONT) - 1); 5881553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 5891553Srgrimes (void) write(fo, "\n", 1); 5901553Srgrimes } 5911553Srgrimes (void) close(fo); 5921553Srgrimes } 5931553Srgrimes prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 5941553Srgrimes av[1] = pxwidth; 5951553Srgrimes av[2] = pxlength; 5961553Srgrimes n = 3; 5971553Srgrimes break; 5981553Srgrimes case 'c': /* print cifplot output */ 5991553Srgrimes prog = CF; 6001553Srgrimes av[1] = pxwidth; 6011553Srgrimes av[2] = pxlength; 6021553Srgrimes n = 3; 6031553Srgrimes break; 6041553Srgrimes case 'g': /* print plot(1G) output */ 6051553Srgrimes prog = GF; 6061553Srgrimes av[1] = pxwidth; 6071553Srgrimes av[2] = pxlength; 6081553Srgrimes n = 3; 6091553Srgrimes break; 6101553Srgrimes case 'v': /* print raster output */ 6111553Srgrimes prog = VF; 6121553Srgrimes av[1] = pxwidth; 6131553Srgrimes av[2] = pxlength; 6141553Srgrimes n = 3; 6151553Srgrimes break; 6161553Srgrimes default: 6171553Srgrimes (void) close(fi); 6181553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 6191553Srgrimes printer, format); 6201553Srgrimes return(ERROR); 6211553Srgrimes } 6221553Srgrimes if ((av[0] = rindex(prog, '/')) != NULL) 6231553Srgrimes av[0]++; 6241553Srgrimes else 6251553Srgrimes av[0] = prog; 6261553Srgrimes av[n++] = "-n"; 6271553Srgrimes av[n++] = logname; 6281553Srgrimes av[n++] = "-h"; 6291553Srgrimes av[n++] = fromhost; 6301553Srgrimes av[n++] = AF; 6311553Srgrimes av[n] = 0; 6321553Srgrimes fo = pfd; 6331553Srgrimes if (ofilter > 0) { /* stop output filter */ 6341553Srgrimes write(ofd, "\031\1", 2); 6351553Srgrimes while ((pid = 6361553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 6371553Srgrimes ; 6381553Srgrimes if (status.w_stopval != WSTOPPED) { 6391553Srgrimes (void) close(fi); 6401553Srgrimes syslog(LOG_WARNING, "%s: output filter died (%d)", 6411553Srgrimes printer, status.w_retcode); 6421553Srgrimes return(REPRINT); 6431553Srgrimes } 6441553Srgrimes stopped++; 6451553Srgrimes } 6461553Srgrimesstart: 6471553Srgrimes if ((child = dofork(DORETURN)) == 0) { /* child */ 6481553Srgrimes dup2(fi, 0); 6491553Srgrimes dup2(fo, 1); 6501553Srgrimes n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 6511553Srgrimes if (n >= 0) 6521553Srgrimes dup2(n, 2); 6531553Srgrimes for (n = 3; n < NOFILE; n++) 6541553Srgrimes (void) close(n); 6551553Srgrimes execv(prog, av); 6561553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 6571553Srgrimes exit(2); 6581553Srgrimes } 6591553Srgrimes (void) close(fi); 6601553Srgrimes if (child < 0) 6611553Srgrimes status.w_retcode = 100; 6621553Srgrimes else 6631553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 6641553Srgrimes ; 6651553Srgrimes child = 0; 6661553Srgrimes prchild = 0; 6671553Srgrimes if (stopped) { /* restart output filter */ 6681553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 6691553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 6701553Srgrimes exit(1); 6711553Srgrimes } 6721553Srgrimes } 6731553Srgrimes tof = 0; 6741553Srgrimes 6751553Srgrimes /* Copy filter output to "lf" logfile */ 6761553Srgrimes if (fp = fopen(tempfile, "r")) { 6771553Srgrimes while (fgets(buf, sizeof(buf), fp)) 6781553Srgrimes fputs(buf, stderr); 6791553Srgrimes fclose(fp); 6801553Srgrimes } 6811553Srgrimes 6821553Srgrimes if (!WIFEXITED(status)) { 6831553Srgrimes syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 6841553Srgrimes printer, format, status.w_termsig); 6851553Srgrimes return(ERROR); 6861553Srgrimes } 6871553Srgrimes switch (status.w_retcode) { 6881553Srgrimes case 0: 6891553Srgrimes tof = 1; 6901553Srgrimes return(OK); 6911553Srgrimes case 1: 6921553Srgrimes return(REPRINT); 6931553Srgrimes default: 6941553Srgrimes syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 6951553Srgrimes printer, format, status.w_retcode); 6961553Srgrimes case 2: 6971553Srgrimes return(ERROR); 6981553Srgrimes } 6991553Srgrimes} 7001553Srgrimes 7011553Srgrimes/* 7021553Srgrimes * Send the daemon control file (cf) and any data files. 7031553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 7041553Srgrimes * 0 if all is well. 7051553Srgrimes */ 7061553Srgrimesstatic int 7071553Srgrimessendit(file) 7081553Srgrimes char *file; 7091553Srgrimes{ 7101553Srgrimes register int i, err = OK; 7111553Srgrimes char *cp, last[BUFSIZ]; 7121553Srgrimes 7131553Srgrimes /* 7141553Srgrimes * open control file 7151553Srgrimes */ 7161553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 7171553Srgrimes return(OK); 7181553Srgrimes /* 7191553Srgrimes * read the control file for work to do 7201553Srgrimes * 7211553Srgrimes * file format -- first character in the line is a command 7221553Srgrimes * rest of the line is the argument. 7231553Srgrimes * commands of interest are: 7241553Srgrimes * 7251553Srgrimes * a-z -- "file name" name of file to print 7261553Srgrimes * U -- "unlink" name of file to remove 7271553Srgrimes * (after we print it. (Pass 2 only)). 7281553Srgrimes */ 7291553Srgrimes 7301553Srgrimes /* 7311553Srgrimes * pass 1 7321553Srgrimes */ 7331553Srgrimes while (getline(cfp)) { 7341553Srgrimes again: 7351553Srgrimes if (line[0] == 'S') { 7361553Srgrimes cp = line+1; 7371553Srgrimes i = 0; 7381553Srgrimes while (*cp >= '0' && *cp <= '9') 7391553Srgrimes i = i * 10 + (*cp++ - '0'); 7401553Srgrimes fdev = i; 7411553Srgrimes cp++; 7421553Srgrimes i = 0; 7431553Srgrimes while (*cp >= '0' && *cp <= '9') 7441553Srgrimes i = i * 10 + (*cp++ - '0'); 7451553Srgrimes fino = i; 7461553Srgrimes continue; 7471553Srgrimes } 7481553Srgrimes if (line[0] >= 'a' && line[0] <= 'z') { 7491553Srgrimes strcpy(last, line); 7501553Srgrimes while (i = getline(cfp)) 7511553Srgrimes if (strcmp(last, line)) 7521553Srgrimes break; 7531553Srgrimes switch (sendfile('\3', last+1)) { 7541553Srgrimes case OK: 7551553Srgrimes if (i) 7561553Srgrimes goto again; 7571553Srgrimes break; 7581553Srgrimes case REPRINT: 7591553Srgrimes (void) fclose(cfp); 7601553Srgrimes return(REPRINT); 7611553Srgrimes case ACCESS: 7621553Srgrimes sendmail(logname, ACCESS); 7631553Srgrimes case ERROR: 7641553Srgrimes err = ERROR; 7651553Srgrimes } 7661553Srgrimes break; 7671553Srgrimes } 7681553Srgrimes } 7691553Srgrimes if (err == OK && sendfile('\2', file) > 0) { 7701553Srgrimes (void) fclose(cfp); 7711553Srgrimes return(REPRINT); 7721553Srgrimes } 7731553Srgrimes /* 7741553Srgrimes * pass 2 7751553Srgrimes */ 7761553Srgrimes fseek(cfp, 0L, 0); 7771553Srgrimes while (getline(cfp)) 7781553Srgrimes if (line[0] == 'U') 7791553Srgrimes (void) unlink(line+1); 7801553Srgrimes /* 7811553Srgrimes * clean-up in case another control file exists 7821553Srgrimes */ 7831553Srgrimes (void) fclose(cfp); 7841553Srgrimes (void) unlink(file); 7851553Srgrimes return(err); 7861553Srgrimes} 7871553Srgrimes 7881553Srgrimes/* 7891553Srgrimes * Send a data file to the remote machine and spool it. 7901553Srgrimes * Return positive if we should try resending. 7911553Srgrimes */ 7921553Srgrimesstatic int 7931553Srgrimessendfile(type, file) 7941553Srgrimes int type; 7951553Srgrimes char *file; 7961553Srgrimes{ 7971553Srgrimes register int f, i, amt; 7981553Srgrimes struct stat stb; 7991553Srgrimes char buf[BUFSIZ]; 8001553Srgrimes int sizerr, resp; 8011553Srgrimes 8021553Srgrimes if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 8031553Srgrimes return(ERROR); 8041553Srgrimes /* 8051553Srgrimes * Check to see if data file is a symbolic link. If so, it should 8061553Srgrimes * still point to the same file or someone is trying to print something 8071553Srgrimes * he shouldn't. 8081553Srgrimes */ 8091553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 8101553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 8111553Srgrimes return(ACCESS); 8121553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 8131553Srgrimes amt = strlen(buf); 8141553Srgrimes for (i = 0; ; i++) { 8151553Srgrimes if (write(pfd, buf, amt) != amt || 8161553Srgrimes (resp = response()) < 0 || resp == '\1') { 8171553Srgrimes (void) close(f); 8181553Srgrimes return(REPRINT); 8191553Srgrimes } else if (resp == '\0') 8201553Srgrimes break; 8211553Srgrimes if (i == 0) 8221553Srgrimes pstatus("no space on remote; waiting for queue to drain"); 8231553Srgrimes if (i == 10) 8241553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 8251553Srgrimes printer, RM); 8261553Srgrimes sleep(5 * 60); 8271553Srgrimes } 8281553Srgrimes if (i) 8291553Srgrimes pstatus("sending to %s", RM); 8301553Srgrimes sizerr = 0; 8311553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 8321553Srgrimes amt = BUFSIZ; 8331553Srgrimes if (i + amt > stb.st_size) 8341553Srgrimes amt = stb.st_size - i; 8351553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 8361553Srgrimes sizerr = 1; 8371553Srgrimes if (write(pfd, buf, amt) != amt) { 8381553Srgrimes (void) close(f); 8391553Srgrimes return(REPRINT); 8401553Srgrimes } 8411553Srgrimes } 8421553Srgrimes 8431553Srgrimes 8441553Srgrimes 8451553Srgrimes 8461553Srgrimes (void) close(f); 8471553Srgrimes if (sizerr) { 8481553Srgrimes syslog(LOG_INFO, "%s: %s: changed size", printer, file); 8491553Srgrimes /* tell recvjob to ignore this file */ 8501553Srgrimes (void) write(pfd, "\1", 1); 8511553Srgrimes return(ERROR); 8521553Srgrimes } 8531553Srgrimes if (write(pfd, "", 1) != 1 || response()) 8541553Srgrimes return(REPRINT); 8551553Srgrimes return(OK); 8561553Srgrimes} 8571553Srgrimes 8581553Srgrimes/* 8591553Srgrimes * Check to make sure there have been no errors and that both programs 8601553Srgrimes * are in sync with eachother. 8611553Srgrimes * Return non-zero if the connection was lost. 8621553Srgrimes */ 8631553Srgrimesstatic char 8641553Srgrimesresponse() 8651553Srgrimes{ 8661553Srgrimes char resp; 8671553Srgrimes 8681553Srgrimes if (read(pfd, &resp, 1) != 1) { 8691553Srgrimes syslog(LOG_INFO, "%s: lost connection", printer); 8701553Srgrimes return(-1); 8711553Srgrimes } 8721553Srgrimes return(resp); 8731553Srgrimes} 8741553Srgrimes 8751553Srgrimes/* 8761553Srgrimes * Banner printing stuff 8771553Srgrimes */ 8781553Srgrimesstatic void 8791553Srgrimesbanner(name1, name2) 8801553Srgrimes char *name1, *name2; 8811553Srgrimes{ 8821553Srgrimes time_t tvec; 8831553Srgrimes extern char *ctime(); 8841553Srgrimes 8851553Srgrimes time(&tvec); 8861553Srgrimes if (!SF && !tof) 8871553Srgrimes (void) write(ofd, FF, strlen(FF)); 8881553Srgrimes if (SB) { /* short banner only */ 8891553Srgrimes if (class[0]) { 8901553Srgrimes (void) write(ofd, class, strlen(class)); 8911553Srgrimes (void) write(ofd, ":", 1); 8921553Srgrimes } 8931553Srgrimes (void) write(ofd, name1, strlen(name1)); 8941553Srgrimes (void) write(ofd, " Job: ", 7); 8951553Srgrimes (void) write(ofd, name2, strlen(name2)); 8961553Srgrimes (void) write(ofd, " Date: ", 8); 8971553Srgrimes (void) write(ofd, ctime(&tvec), 24); 8981553Srgrimes (void) write(ofd, "\n", 1); 8991553Srgrimes } else { /* normal banner */ 9001553Srgrimes (void) write(ofd, "\n\n\n", 3); 9011553Srgrimes scan_out(ofd, name1, '\0'); 9021553Srgrimes (void) write(ofd, "\n\n", 2); 9031553Srgrimes scan_out(ofd, name2, '\0'); 9041553Srgrimes if (class[0]) { 9051553Srgrimes (void) write(ofd,"\n\n\n",3); 9061553Srgrimes scan_out(ofd, class, '\0'); 9071553Srgrimes } 9081553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 9091553Srgrimes (void) write(ofd, name2, strlen(name2)); 9101553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 9111553Srgrimes (void) write(ofd, ctime(&tvec), 24); 9121553Srgrimes (void) write(ofd, "\n", 1); 9131553Srgrimes } 9141553Srgrimes if (!SF) 9151553Srgrimes (void) write(ofd, FF, strlen(FF)); 9161553Srgrimes tof = 1; 9171553Srgrimes} 9181553Srgrimes 9191553Srgrimesstatic char * 9201553Srgrimesscnline(key, p, c) 9211553Srgrimes register int key; 9221553Srgrimes register char *p; 9231553Srgrimes int c; 9241553Srgrimes{ 9251553Srgrimes register scnwidth; 9261553Srgrimes 9271553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 9281553Srgrimes key <<= 1; 9291553Srgrimes *p++ = key & 0200 ? c : BACKGND; 9301553Srgrimes } 9311553Srgrimes return (p); 9321553Srgrimes} 9331553Srgrimes 9341553Srgrimes#define TRC(q) (((q)-' ')&0177) 9351553Srgrimes 9361553Srgrimesstatic void 9371553Srgrimesscan_out(scfd, scsp, dlm) 9381553Srgrimes int scfd, dlm; 9391553Srgrimes char *scsp; 9401553Srgrimes{ 9411553Srgrimes register char *strp; 9421553Srgrimes register nchrs, j; 9431553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 9441553Srgrimes int d, scnhgt; 9451553Srgrimes extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 9461553Srgrimes 9471553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 9481553Srgrimes strp = &outbuf[0]; 9491553Srgrimes sp = scsp; 9501553Srgrimes for (nchrs = 0; ; ) { 9511553Srgrimes d = dropit(c = TRC(cc = *sp++)); 9521553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 9531553Srgrimes for (j = WIDTH; --j;) 9541553Srgrimes *strp++ = BACKGND; 9551553Srgrimes else 9561553Srgrimes strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 9571553Srgrimes if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 9581553Srgrimes break; 9591553Srgrimes *strp++ = BACKGND; 9601553Srgrimes *strp++ = BACKGND; 9611553Srgrimes } 9621553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 9631553Srgrimes ; 9641553Srgrimes strp++; 9651553Srgrimes *strp++ = '\n'; 9661553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 9671553Srgrimes } 9681553Srgrimes} 9691553Srgrimes 9701553Srgrimesstatic int 9711553Srgrimesdropit(c) 9721553Srgrimes int c; 9731553Srgrimes{ 9741553Srgrimes switch(c) { 9751553Srgrimes 9761553Srgrimes case TRC('_'): 9771553Srgrimes case TRC(';'): 9781553Srgrimes case TRC(','): 9791553Srgrimes case TRC('g'): 9801553Srgrimes case TRC('j'): 9811553Srgrimes case TRC('p'): 9821553Srgrimes case TRC('q'): 9831553Srgrimes case TRC('y'): 9841553Srgrimes return (DROP); 9851553Srgrimes 9861553Srgrimes default: 9871553Srgrimes return (0); 9881553Srgrimes } 9891553Srgrimes} 9901553Srgrimes 9911553Srgrimes/* 9921553Srgrimes * sendmail --- 9931553Srgrimes * tell people about job completion 9941553Srgrimes */ 9951553Srgrimesstatic void 9961553Srgrimessendmail(user, bombed) 9971553Srgrimes char *user; 9981553Srgrimes int bombed; 9991553Srgrimes{ 10001553Srgrimes register int i; 10011553Srgrimes int p[2], s; 10021553Srgrimes register char *cp; 10031553Srgrimes char buf[100]; 10041553Srgrimes struct stat stb; 10051553Srgrimes FILE *fp; 10061553Srgrimes 10071553Srgrimes pipe(p); 10081553Srgrimes if ((s = dofork(DORETURN)) == 0) { /* child */ 10091553Srgrimes dup2(p[0], 0); 10101553Srgrimes for (i = 3; i < NOFILE; i++) 10111553Srgrimes (void) close(i); 10121553Srgrimes if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 10131553Srgrimes cp++; 10141553Srgrimes else 10151553Srgrimes cp = _PATH_SENDMAIL; 10161553Srgrimes sprintf(buf, "%s@%s", user, fromhost); 10171553Srgrimes execl(_PATH_SENDMAIL, cp, buf, 0); 10181553Srgrimes exit(0); 10191553Srgrimes } else if (s > 0) { /* parent */ 10201553Srgrimes dup2(p[1], 1); 10211553Srgrimes printf("To: %s@%s\n", user, fromhost); 10221553Srgrimes printf("Subject: printer job\n\n"); 10231553Srgrimes printf("Your printer job "); 10241553Srgrimes if (*jobname) 10251553Srgrimes printf("(%s) ", jobname); 10261553Srgrimes switch (bombed) { 10271553Srgrimes case OK: 10281553Srgrimes printf("\ncompleted successfully\n"); 10291553Srgrimes break; 10301553Srgrimes default: 10311553Srgrimes case FATALERR: 10321553Srgrimes printf("\ncould not be printed\n"); 10331553Srgrimes break; 10341553Srgrimes case NOACCT: 10351553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 10361553Srgrimes break; 10371553Srgrimes case FILTERERR: 10381553Srgrimes if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 10391553Srgrimes (fp = fopen(tempfile, "r")) == NULL) { 10401553Srgrimes printf("\nwas printed but had some errors\n"); 10411553Srgrimes break; 10421553Srgrimes } 10431553Srgrimes printf("\nwas printed but had the following errors:\n"); 10441553Srgrimes while ((i = getc(fp)) != EOF) 10451553Srgrimes putchar(i); 10461553Srgrimes (void) fclose(fp); 10471553Srgrimes break; 10481553Srgrimes case ACCESS: 10491553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 10501553Srgrimes } 10511553Srgrimes fflush(stdout); 10521553Srgrimes (void) close(1); 10531553Srgrimes } 10541553Srgrimes (void) close(p[0]); 10551553Srgrimes (void) close(p[1]); 10561553Srgrimes wait(&s); 10571553Srgrimes} 10581553Srgrimes 10591553Srgrimes/* 10601553Srgrimes * dofork - fork with retries on failure 10611553Srgrimes */ 10621553Srgrimesstatic int 10631553Srgrimesdofork(action) 10641553Srgrimes int action; 10651553Srgrimes{ 10661553Srgrimes register int i, pid; 10671553Srgrimes 10681553Srgrimes for (i = 0; i < 20; i++) { 10691553Srgrimes if ((pid = fork()) < 0) { 10701553Srgrimes sleep((unsigned)(i*i)); 10711553Srgrimes continue; 10721553Srgrimes } 10731553Srgrimes /* 10741553Srgrimes * Child should run as daemon instead of root 10751553Srgrimes */ 10761553Srgrimes if (pid == 0) 10771553Srgrimes setuid(DU); 10781553Srgrimes return(pid); 10791553Srgrimes } 10801553Srgrimes syslog(LOG_ERR, "can't fork"); 10811553Srgrimes 10821553Srgrimes switch (action) { 10831553Srgrimes case DORETURN: 10841553Srgrimes return (-1); 10851553Srgrimes default: 10861553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 10871553Srgrimes /*FALL THRU*/ 10881553Srgrimes case DOABORT: 10891553Srgrimes exit(1); 10901553Srgrimes } 10911553Srgrimes /*NOTREACHED*/ 10921553Srgrimes} 10931553Srgrimes 10941553Srgrimes/* 10951553Srgrimes * Kill child processes to abort current job. 10961553Srgrimes */ 10971553Srgrimesstatic void 10981553Srgrimesabortpr(signo) 10991553Srgrimes int signo; 11001553Srgrimes{ 11011553Srgrimes (void) unlink(tempfile); 11021553Srgrimes kill(0, SIGINT); 11031553Srgrimes if (ofilter > 0) 11041553Srgrimes kill(ofilter, SIGCONT); 11051553Srgrimes while (wait(NULL) > 0) 11061553Srgrimes ; 11071553Srgrimes exit(0); 11081553Srgrimes} 11091553Srgrimes 11101553Srgrimesstatic void 11111553Srgrimesinit() 11121553Srgrimes{ 11131553Srgrimes int status; 11141553Srgrimes char *s; 11151553Srgrimes 11161553Srgrimes if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 11171553Srgrimes syslog(LOG_ERR, "can't open printer description file"); 11181553Srgrimes exit(1); 11191553Srgrimes } else if (status == -1) { 11201553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 11211553Srgrimes exit(1); 11221553Srgrimes } else if (status == -3) 11231553Srgrimes fatal("potential reference loop detected in printcap file"); 11241553Srgrimes 11251553Srgrimes if (cgetstr(bp, "lp", &LP) == -1) 11261553Srgrimes LP = _PATH_DEFDEVLP; 11271553Srgrimes if (cgetstr(bp, "rp", &RP) == -1) 11281553Srgrimes RP = DEFLP; 11291553Srgrimes if (cgetstr(bp, "lo", &LO) == -1) 11301553Srgrimes LO = DEFLOCK; 11311553Srgrimes if (cgetstr(bp, "st", &ST) == -1) 11321553Srgrimes ST = DEFSTAT; 11331553Srgrimes if (cgetstr(bp, "lf", &LF) == -1) 11341553Srgrimes LF = _PATH_CONSOLE; 11351553Srgrimes if (cgetstr(bp, "sd", &SD) == -1) 11361553Srgrimes SD = _PATH_DEFSPOOL; 11371553Srgrimes if (cgetnum(bp, "du", &DU) < 0) 11381553Srgrimes DU = DEFUID; 11391553Srgrimes if (cgetstr(bp,"ff", &FF) == -1) 11401553Srgrimes FF = DEFFF; 11411553Srgrimes if (cgetnum(bp, "pw", &PW) < 0) 11421553Srgrimes PW = DEFWIDTH; 11431553Srgrimes sprintf(&width[2], "%d", PW); 11441553Srgrimes if (cgetnum(bp, "pl", &PL) < 0) 11451553Srgrimes PL = DEFLENGTH; 11461553Srgrimes sprintf(&length[2], "%d", PL); 11471553Srgrimes if (cgetnum(bp,"px", &PX) < 0) 11481553Srgrimes PX = 0; 11491553Srgrimes sprintf(&pxwidth[2], "%d", PX); 11501553Srgrimes if (cgetnum(bp, "py", &PY) < 0) 11511553Srgrimes PY = 0; 11521553Srgrimes sprintf(&pxlength[2], "%d", PY); 11531553Srgrimes cgetstr(bp, "rm", &RM); 11541553Srgrimes if (s = checkremote()) 11551553Srgrimes syslog(LOG_WARNING, s); 11561553Srgrimes 11571553Srgrimes cgetstr(bp, "af", &AF); 11581553Srgrimes cgetstr(bp, "of", &OF); 11591553Srgrimes cgetstr(bp, "if", &IF); 11601553Srgrimes cgetstr(bp, "rf", &RF); 11611553Srgrimes cgetstr(bp, "tf", &TF); 11621553Srgrimes cgetstr(bp, "nf", &NF); 11631553Srgrimes cgetstr(bp, "df", &DF); 11641553Srgrimes cgetstr(bp, "gf", &GF); 11651553Srgrimes cgetstr(bp, "vf", &VF); 11661553Srgrimes cgetstr(bp, "cf", &CF); 11671553Srgrimes cgetstr(bp, "tr", &TR); 11681553Srgrimes 11691553Srgrimes RS = (cgetcap(bp, "rs", ':') != NULL); 11701553Srgrimes SF = (cgetcap(bp, "sf", ':') != NULL); 11711553Srgrimes SH = (cgetcap(bp, "sh", ':') != NULL); 11721553Srgrimes SB = (cgetcap(bp, "sb", ':') != NULL); 11731553Srgrimes HL = (cgetcap(bp, "hl", ':') != NULL); 11741553Srgrimes RW = (cgetcap(bp, "rw", ':') != NULL); 11751553Srgrimes 11761553Srgrimes cgetnum(bp, "br", &BR); 11771553Srgrimes if (cgetnum(bp, "fc", &FC) < 0) 11781553Srgrimes FC = 0; 11791553Srgrimes if (cgetnum(bp, "fs", &FS) < 0) 11801553Srgrimes FS = 0; 11811553Srgrimes if (cgetnum(bp, "xc", &XC) < 0) 11821553Srgrimes XC = 0; 11831553Srgrimes if (cgetnum(bp, "xs", &XS) < 0) 11841553Srgrimes XS = 0; 11851553Srgrimes 11861553Srgrimes tof = (cgetcap(bp, "fo", ':') == NULL); 11871553Srgrimes} 11881553Srgrimes 11891553Srgrimes/* 11901553Srgrimes * Acquire line printer or remote connection. 11911553Srgrimes */ 11921553Srgrimesstatic void 11931553Srgrimesopenpr() 11941553Srgrimes{ 11951553Srgrimes register int i, n; 11961553Srgrimes int resp; 11971553Srgrimes 11981553Srgrimes if (!sendtorem && *LP) { 11991553Srgrimes for (i = 1; ; i = i < 32 ? i << 1 : i) { 12001553Srgrimes pfd = open(LP, RW ? O_RDWR : O_WRONLY); 12011553Srgrimes if (pfd >= 0) 12021553Srgrimes break; 12031553Srgrimes if (errno == ENOENT) { 12041553Srgrimes syslog(LOG_ERR, "%s: %m", LP); 12051553Srgrimes exit(1); 12061553Srgrimes } 12071553Srgrimes if (i == 1) 12081553Srgrimes pstatus("waiting for %s to become ready (offline ?)", printer); 12091553Srgrimes sleep(i); 12101553Srgrimes } 12111553Srgrimes if (isatty(pfd)) 12121553Srgrimes setty(); 12131553Srgrimes pstatus("%s is ready and printing", printer); 12141553Srgrimes } else if (RM != NULL) { 12151553Srgrimes for (i = 1; ; i = i < 256 ? i << 1 : i) { 12161553Srgrimes resp = -1; 12171553Srgrimes pfd = getport(RM); 12181553Srgrimes if (pfd >= 0) { 12191553Srgrimes (void) sprintf(line, "\2%s\n", RP); 12201553Srgrimes n = strlen(line); 12211553Srgrimes if (write(pfd, line, n) == n && 12221553Srgrimes (resp = response()) == '\0') 12231553Srgrimes break; 12241553Srgrimes (void) close(pfd); 12251553Srgrimes } 12261553Srgrimes if (i == 1) { 12271553Srgrimes if (resp < 0) 12281553Srgrimes pstatus("waiting for %s to come up", RM); 12291553Srgrimes else { 12301553Srgrimes pstatus("waiting for queue to be enabled on %s", RM); 12311553Srgrimes i = 256; 12321553Srgrimes } 12331553Srgrimes } 12341553Srgrimes sleep(i); 12351553Srgrimes } 12361553Srgrimes pstatus("sending to %s", RM); 12371553Srgrimes remote = 1; 12381553Srgrimes } else { 12391553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 12401553Srgrimes printer); 12411553Srgrimes exit(1); 12421553Srgrimes } 12431553Srgrimes /* 12441553Srgrimes * Start up an output filter, if needed. 12451553Srgrimes */ 12461553Srgrimes if (!remote && OF) { 12471553Srgrimes int p[2]; 12481553Srgrimes char *cp; 12491553Srgrimes 12501553Srgrimes pipe(p); 12511553Srgrimes if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 12521553Srgrimes dup2(p[0], 0); /* pipe is std in */ 12531553Srgrimes dup2(pfd, 1); /* printer is std out */ 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 12721553Srgrimesstruct bauds { 12731553Srgrimes int baud; 12741553Srgrimes int speed; 12751553Srgrimes} bauds[] = { 12761553Srgrimes 50, B50, 12771553Srgrimes 75, B75, 12781553Srgrimes 110, B110, 12791553Srgrimes 134, B134, 12801553Srgrimes 150, B150, 12811553Srgrimes 200, B200, 12821553Srgrimes 300, B300, 12831553Srgrimes 600, B600, 12841553Srgrimes 1200, B1200, 12851553Srgrimes 1800, B1800, 12861553Srgrimes 2400, B2400, 12871553Srgrimes 4800, B4800, 12881553Srgrimes 9600, B9600, 12891553Srgrimes 19200, EXTA, 12901553Srgrimes 38400, EXTB, 12911553Srgrimes 0, 0 12921553Srgrimes}; 12931553Srgrimes 12941553Srgrimes/* 12951553Srgrimes * setup tty lines. 12961553Srgrimes */ 12971553Srgrimesstatic void 12981553Srgrimessetty() 12991553Srgrimes{ 13001553Srgrimes struct sgttyb ttybuf; 13011553Srgrimes register struct bauds *bp; 13021553Srgrimes 13031553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 13041553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 13051553Srgrimes exit(1); 13061553Srgrimes } 13071553Srgrimes if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 13081553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 13091553Srgrimes exit(1); 13101553Srgrimes } 13111553Srgrimes if (BR > 0) { 13121553Srgrimes for (bp = bauds; bp->baud; bp++) 13131553Srgrimes if (BR == bp->baud) 13141553Srgrimes break; 13151553Srgrimes if (!bp->baud) { 13161553Srgrimes syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 13171553Srgrimes exit(1); 13181553Srgrimes } 13191553Srgrimes ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 13201553Srgrimes } 13211553Srgrimes ttybuf.sg_flags &= ~FC; 13221553Srgrimes ttybuf.sg_flags |= FS; 13231553Srgrimes if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 13241553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 13251553Srgrimes exit(1); 13261553Srgrimes } 13271553Srgrimes if (XC) { 13281553Srgrimes if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 13291553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 13301553Srgrimes exit(1); 13311553Srgrimes } 13321553Srgrimes } 13331553Srgrimes if (XS) { 13341553Srgrimes if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 13351553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 13361553Srgrimes exit(1); 13371553Srgrimes } 13381553Srgrimes } 13391553Srgrimes} 13401553Srgrimes 13411553Srgrimes#if __STDC__ 13421553Srgrimes#include <stdarg.h> 13431553Srgrimes#else 13441553Srgrimes#include <varargs.h> 13451553Srgrimes#endif 13461553Srgrimes 13471553Srgrimesvoid 13481553Srgrimes#if __STDC__ 13491553Srgrimespstatus(const char *msg, ...) 13501553Srgrimes#else 13511553Srgrimespstatus(msg, va_alist) 13521553Srgrimes char *msg; 13531553Srgrimes va_dcl 13541553Srgrimes#endif 13551553Srgrimes{ 13561553Srgrimes register int fd; 13571553Srgrimes char buf[BUFSIZ]; 13581553Srgrimes va_list ap; 13591553Srgrimes#if __STDC__ 13601553Srgrimes va_start(ap, msg); 13611553Srgrimes#else 13621553Srgrimes va_start(ap); 13631553Srgrimes#endif 13641553Srgrimes 13651553Srgrimes umask(0); 13661553Srgrimes fd = open(ST, O_WRONLY|O_CREAT, 0664); 13671553Srgrimes if (fd < 0 || flock(fd, LOCK_EX) < 0) { 13681553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, ST); 13691553Srgrimes exit(1); 13701553Srgrimes } 13711553Srgrimes ftruncate(fd, 0); 13721553Srgrimes (void)vsnprintf(buf, sizeof(buf), msg, ap); 13731553Srgrimes va_end(ap); 13741553Srgrimes strcat(buf, "\n"); 13751553Srgrimes (void) write(fd, buf, strlen(buf)); 13761553Srgrimes (void) close(fd); 13771553Srgrimes} 1378