printjob.c revision 5445
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 : " "; 5325445Sjoerg av[5] = "-F"; 5335445Sjoerg av[6] = 0; 5341553Srgrimes fo = ofd; 5351553Srgrimes goto start; 5361553Srgrimes } 5371553Srgrimes pipe(p); 5381553Srgrimes if ((prchild = dofork(DORETURN)) == 0) { /* child */ 5391553Srgrimes dup2(fi, 0); /* file is stdin */ 5401553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 5411553Srgrimes for (n = 3; n < NOFILE; n++) 5421553Srgrimes (void) close(n); 5431553Srgrimes execl(_PATH_PR, "pr", width, length, 5445445Sjoerg "-h", *title ? title : " ", "-F", 0); 5451553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 5461553Srgrimes exit(2); 5471553Srgrimes } 5481553Srgrimes (void) close(p[1]); /* close output side */ 5491553Srgrimes (void) close(fi); 5501553Srgrimes if (prchild < 0) { 5511553Srgrimes prchild = 0; 5521553Srgrimes (void) close(p[0]); 5531553Srgrimes return(ERROR); 5541553Srgrimes } 5551553Srgrimes fi = p[0]; /* use pipe for input */ 5561553Srgrimes case 'f': /* print plain text file */ 5571553Srgrimes prog = IF; 5581553Srgrimes av[1] = width; 5591553Srgrimes av[2] = length; 5601553Srgrimes av[3] = indent; 5611553Srgrimes n = 4; 5621553Srgrimes break; 5631553Srgrimes case 'l': /* like 'f' but pass control characters */ 5641553Srgrimes prog = IF; 5651553Srgrimes av[1] = "-c"; 5661553Srgrimes av[2] = width; 5671553Srgrimes av[3] = length; 5681553Srgrimes av[4] = indent; 5691553Srgrimes n = 5; 5701553Srgrimes break; 5711553Srgrimes case 'r': /* print a fortran text file */ 5721553Srgrimes prog = RF; 5731553Srgrimes av[1] = width; 5741553Srgrimes av[2] = length; 5751553Srgrimes n = 3; 5761553Srgrimes break; 5771553Srgrimes case 't': /* print troff output */ 5781553Srgrimes case 'n': /* print ditroff output */ 5791553Srgrimes case 'd': /* print tex output */ 5801553Srgrimes (void) unlink(".railmag"); 5811553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 5821553Srgrimes syslog(LOG_ERR, "%s: cannot create .railmag", printer); 5831553Srgrimes (void) unlink(".railmag"); 5841553Srgrimes } else { 5851553Srgrimes for (n = 0; n < 4; n++) { 5861553Srgrimes if (fonts[n][0] != '/') 5871553Srgrimes (void) write(fo, _PATH_VFONT, 5881553Srgrimes sizeof(_PATH_VFONT) - 1); 5891553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 5901553Srgrimes (void) write(fo, "\n", 1); 5911553Srgrimes } 5921553Srgrimes (void) close(fo); 5931553Srgrimes } 5941553Srgrimes prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 5951553Srgrimes av[1] = pxwidth; 5961553Srgrimes av[2] = pxlength; 5971553Srgrimes n = 3; 5981553Srgrimes break; 5991553Srgrimes case 'c': /* print cifplot output */ 6001553Srgrimes prog = CF; 6011553Srgrimes av[1] = pxwidth; 6021553Srgrimes av[2] = pxlength; 6031553Srgrimes n = 3; 6041553Srgrimes break; 6051553Srgrimes case 'g': /* print plot(1G) output */ 6061553Srgrimes prog = GF; 6071553Srgrimes av[1] = pxwidth; 6081553Srgrimes av[2] = pxlength; 6091553Srgrimes n = 3; 6101553Srgrimes break; 6111553Srgrimes case 'v': /* print raster output */ 6121553Srgrimes prog = VF; 6131553Srgrimes av[1] = pxwidth; 6141553Srgrimes av[2] = pxlength; 6151553Srgrimes n = 3; 6161553Srgrimes break; 6171553Srgrimes default: 6181553Srgrimes (void) close(fi); 6191553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 6201553Srgrimes printer, format); 6211553Srgrimes return(ERROR); 6221553Srgrimes } 6231553Srgrimes if ((av[0] = rindex(prog, '/')) != NULL) 6241553Srgrimes av[0]++; 6251553Srgrimes else 6261553Srgrimes av[0] = prog; 6271553Srgrimes av[n++] = "-n"; 6281553Srgrimes av[n++] = logname; 6291553Srgrimes av[n++] = "-h"; 6301553Srgrimes av[n++] = fromhost; 6311553Srgrimes av[n++] = AF; 6321553Srgrimes av[n] = 0; 6331553Srgrimes fo = pfd; 6341553Srgrimes if (ofilter > 0) { /* stop output filter */ 6351553Srgrimes write(ofd, "\031\1", 2); 6361553Srgrimes while ((pid = 6371553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 6381553Srgrimes ; 6391553Srgrimes if (status.w_stopval != WSTOPPED) { 6401553Srgrimes (void) close(fi); 6411553Srgrimes syslog(LOG_WARNING, "%s: output filter died (%d)", 6421553Srgrimes printer, status.w_retcode); 6431553Srgrimes return(REPRINT); 6441553Srgrimes } 6451553Srgrimes stopped++; 6461553Srgrimes } 6471553Srgrimesstart: 6481553Srgrimes if ((child = dofork(DORETURN)) == 0) { /* child */ 6491553Srgrimes dup2(fi, 0); 6501553Srgrimes dup2(fo, 1); 6511553Srgrimes n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 6521553Srgrimes if (n >= 0) 6531553Srgrimes dup2(n, 2); 6541553Srgrimes for (n = 3; n < NOFILE; n++) 6551553Srgrimes (void) close(n); 6561553Srgrimes execv(prog, av); 6571553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 6581553Srgrimes exit(2); 6591553Srgrimes } 6601553Srgrimes (void) close(fi); 6611553Srgrimes if (child < 0) 6621553Srgrimes status.w_retcode = 100; 6631553Srgrimes else 6641553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 6651553Srgrimes ; 6661553Srgrimes child = 0; 6671553Srgrimes prchild = 0; 6681553Srgrimes if (stopped) { /* restart output filter */ 6691553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 6701553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 6711553Srgrimes exit(1); 6721553Srgrimes } 6731553Srgrimes } 6741553Srgrimes tof = 0; 6751553Srgrimes 6761553Srgrimes /* Copy filter output to "lf" logfile */ 6771553Srgrimes if (fp = fopen(tempfile, "r")) { 6781553Srgrimes while (fgets(buf, sizeof(buf), fp)) 6791553Srgrimes fputs(buf, stderr); 6801553Srgrimes fclose(fp); 6811553Srgrimes } 6821553Srgrimes 6831553Srgrimes if (!WIFEXITED(status)) { 6841553Srgrimes syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 6851553Srgrimes printer, format, status.w_termsig); 6861553Srgrimes return(ERROR); 6871553Srgrimes } 6881553Srgrimes switch (status.w_retcode) { 6891553Srgrimes case 0: 6901553Srgrimes tof = 1; 6911553Srgrimes return(OK); 6921553Srgrimes case 1: 6931553Srgrimes return(REPRINT); 6941553Srgrimes default: 6951553Srgrimes syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 6961553Srgrimes printer, format, status.w_retcode); 6971553Srgrimes case 2: 6981553Srgrimes return(ERROR); 6991553Srgrimes } 7001553Srgrimes} 7011553Srgrimes 7021553Srgrimes/* 7031553Srgrimes * Send the daemon control file (cf) and any data files. 7041553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 7051553Srgrimes * 0 if all is well. 7061553Srgrimes */ 7071553Srgrimesstatic int 7081553Srgrimessendit(file) 7091553Srgrimes char *file; 7101553Srgrimes{ 7111553Srgrimes register int i, err = OK; 7121553Srgrimes char *cp, last[BUFSIZ]; 7131553Srgrimes 7141553Srgrimes /* 7151553Srgrimes * open control file 7161553Srgrimes */ 7171553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 7181553Srgrimes return(OK); 7191553Srgrimes /* 7201553Srgrimes * read the control file for work to do 7211553Srgrimes * 7221553Srgrimes * file format -- first character in the line is a command 7231553Srgrimes * rest of the line is the argument. 7241553Srgrimes * commands of interest are: 7251553Srgrimes * 7261553Srgrimes * a-z -- "file name" name of file to print 7271553Srgrimes * U -- "unlink" name of file to remove 7281553Srgrimes * (after we print it. (Pass 2 only)). 7291553Srgrimes */ 7301553Srgrimes 7311553Srgrimes /* 7321553Srgrimes * pass 1 7331553Srgrimes */ 7341553Srgrimes while (getline(cfp)) { 7351553Srgrimes again: 7361553Srgrimes if (line[0] == 'S') { 7371553Srgrimes cp = line+1; 7381553Srgrimes i = 0; 7391553Srgrimes while (*cp >= '0' && *cp <= '9') 7401553Srgrimes i = i * 10 + (*cp++ - '0'); 7411553Srgrimes fdev = i; 7421553Srgrimes cp++; 7431553Srgrimes i = 0; 7441553Srgrimes while (*cp >= '0' && *cp <= '9') 7451553Srgrimes i = i * 10 + (*cp++ - '0'); 7461553Srgrimes fino = i; 7471553Srgrimes continue; 7481553Srgrimes } 7491553Srgrimes if (line[0] >= 'a' && line[0] <= 'z') { 7501553Srgrimes strcpy(last, line); 7511553Srgrimes while (i = getline(cfp)) 7521553Srgrimes if (strcmp(last, line)) 7531553Srgrimes break; 7541553Srgrimes switch (sendfile('\3', last+1)) { 7551553Srgrimes case OK: 7561553Srgrimes if (i) 7571553Srgrimes goto again; 7581553Srgrimes break; 7591553Srgrimes case REPRINT: 7601553Srgrimes (void) fclose(cfp); 7611553Srgrimes return(REPRINT); 7621553Srgrimes case ACCESS: 7631553Srgrimes sendmail(logname, ACCESS); 7641553Srgrimes case ERROR: 7651553Srgrimes err = ERROR; 7661553Srgrimes } 7671553Srgrimes break; 7681553Srgrimes } 7691553Srgrimes } 7701553Srgrimes if (err == OK && sendfile('\2', file) > 0) { 7711553Srgrimes (void) fclose(cfp); 7721553Srgrimes return(REPRINT); 7731553Srgrimes } 7741553Srgrimes /* 7751553Srgrimes * pass 2 7761553Srgrimes */ 7771553Srgrimes fseek(cfp, 0L, 0); 7781553Srgrimes while (getline(cfp)) 7791553Srgrimes if (line[0] == 'U') 7801553Srgrimes (void) unlink(line+1); 7811553Srgrimes /* 7821553Srgrimes * clean-up in case another control file exists 7831553Srgrimes */ 7841553Srgrimes (void) fclose(cfp); 7851553Srgrimes (void) unlink(file); 7861553Srgrimes return(err); 7871553Srgrimes} 7881553Srgrimes 7891553Srgrimes/* 7901553Srgrimes * Send a data file to the remote machine and spool it. 7911553Srgrimes * Return positive if we should try resending. 7921553Srgrimes */ 7931553Srgrimesstatic int 7941553Srgrimessendfile(type, file) 7951553Srgrimes int type; 7961553Srgrimes char *file; 7971553Srgrimes{ 7981553Srgrimes register int f, i, amt; 7991553Srgrimes struct stat stb; 8001553Srgrimes char buf[BUFSIZ]; 8011553Srgrimes int sizerr, resp; 8021553Srgrimes 8031553Srgrimes if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 8041553Srgrimes return(ERROR); 8051553Srgrimes /* 8061553Srgrimes * Check to see if data file is a symbolic link. If so, it should 8071553Srgrimes * still point to the same file or someone is trying to print something 8081553Srgrimes * he shouldn't. 8091553Srgrimes */ 8101553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 8111553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 8121553Srgrimes return(ACCESS); 8131553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 8141553Srgrimes amt = strlen(buf); 8151553Srgrimes for (i = 0; ; i++) { 8161553Srgrimes if (write(pfd, buf, amt) != amt || 8171553Srgrimes (resp = response()) < 0 || resp == '\1') { 8181553Srgrimes (void) close(f); 8191553Srgrimes return(REPRINT); 8201553Srgrimes } else if (resp == '\0') 8211553Srgrimes break; 8221553Srgrimes if (i == 0) 8231553Srgrimes pstatus("no space on remote; waiting for queue to drain"); 8241553Srgrimes if (i == 10) 8251553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 8261553Srgrimes printer, RM); 8271553Srgrimes sleep(5 * 60); 8281553Srgrimes } 8291553Srgrimes if (i) 8301553Srgrimes pstatus("sending to %s", RM); 8311553Srgrimes sizerr = 0; 8321553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 8331553Srgrimes amt = BUFSIZ; 8341553Srgrimes if (i + amt > stb.st_size) 8351553Srgrimes amt = stb.st_size - i; 8361553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 8371553Srgrimes sizerr = 1; 8381553Srgrimes if (write(pfd, buf, amt) != amt) { 8391553Srgrimes (void) close(f); 8401553Srgrimes return(REPRINT); 8411553Srgrimes } 8421553Srgrimes } 8431553Srgrimes 8441553Srgrimes 8451553Srgrimes 8461553Srgrimes 8471553Srgrimes (void) close(f); 8481553Srgrimes if (sizerr) { 8491553Srgrimes syslog(LOG_INFO, "%s: %s: changed size", printer, file); 8501553Srgrimes /* tell recvjob to ignore this file */ 8511553Srgrimes (void) write(pfd, "\1", 1); 8521553Srgrimes return(ERROR); 8531553Srgrimes } 8541553Srgrimes if (write(pfd, "", 1) != 1 || response()) 8551553Srgrimes return(REPRINT); 8561553Srgrimes return(OK); 8571553Srgrimes} 8581553Srgrimes 8591553Srgrimes/* 8601553Srgrimes * Check to make sure there have been no errors and that both programs 8611553Srgrimes * are in sync with eachother. 8621553Srgrimes * Return non-zero if the connection was lost. 8631553Srgrimes */ 8641553Srgrimesstatic char 8651553Srgrimesresponse() 8661553Srgrimes{ 8671553Srgrimes char resp; 8681553Srgrimes 8691553Srgrimes if (read(pfd, &resp, 1) != 1) { 8701553Srgrimes syslog(LOG_INFO, "%s: lost connection", printer); 8711553Srgrimes return(-1); 8721553Srgrimes } 8731553Srgrimes return(resp); 8741553Srgrimes} 8751553Srgrimes 8761553Srgrimes/* 8771553Srgrimes * Banner printing stuff 8781553Srgrimes */ 8791553Srgrimesstatic void 8801553Srgrimesbanner(name1, name2) 8811553Srgrimes char *name1, *name2; 8821553Srgrimes{ 8831553Srgrimes time_t tvec; 8841553Srgrimes extern char *ctime(); 8851553Srgrimes 8861553Srgrimes time(&tvec); 8871553Srgrimes if (!SF && !tof) 8881553Srgrimes (void) write(ofd, FF, strlen(FF)); 8891553Srgrimes if (SB) { /* short banner only */ 8901553Srgrimes if (class[0]) { 8911553Srgrimes (void) write(ofd, class, strlen(class)); 8921553Srgrimes (void) write(ofd, ":", 1); 8931553Srgrimes } 8941553Srgrimes (void) write(ofd, name1, strlen(name1)); 8951553Srgrimes (void) write(ofd, " Job: ", 7); 8961553Srgrimes (void) write(ofd, name2, strlen(name2)); 8971553Srgrimes (void) write(ofd, " Date: ", 8); 8981553Srgrimes (void) write(ofd, ctime(&tvec), 24); 8991553Srgrimes (void) write(ofd, "\n", 1); 9001553Srgrimes } else { /* normal banner */ 9011553Srgrimes (void) write(ofd, "\n\n\n", 3); 9021553Srgrimes scan_out(ofd, name1, '\0'); 9031553Srgrimes (void) write(ofd, "\n\n", 2); 9041553Srgrimes scan_out(ofd, name2, '\0'); 9051553Srgrimes if (class[0]) { 9061553Srgrimes (void) write(ofd,"\n\n\n",3); 9071553Srgrimes scan_out(ofd, class, '\0'); 9081553Srgrimes } 9091553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 9101553Srgrimes (void) write(ofd, name2, strlen(name2)); 9111553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 9121553Srgrimes (void) write(ofd, ctime(&tvec), 24); 9131553Srgrimes (void) write(ofd, "\n", 1); 9141553Srgrimes } 9151553Srgrimes if (!SF) 9161553Srgrimes (void) write(ofd, FF, strlen(FF)); 9171553Srgrimes tof = 1; 9181553Srgrimes} 9191553Srgrimes 9201553Srgrimesstatic char * 9211553Srgrimesscnline(key, p, c) 9221553Srgrimes register int key; 9231553Srgrimes register char *p; 9241553Srgrimes int c; 9251553Srgrimes{ 9261553Srgrimes register scnwidth; 9271553Srgrimes 9281553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 9291553Srgrimes key <<= 1; 9301553Srgrimes *p++ = key & 0200 ? c : BACKGND; 9311553Srgrimes } 9321553Srgrimes return (p); 9331553Srgrimes} 9341553Srgrimes 9351553Srgrimes#define TRC(q) (((q)-' ')&0177) 9361553Srgrimes 9371553Srgrimesstatic void 9381553Srgrimesscan_out(scfd, scsp, dlm) 9391553Srgrimes int scfd, dlm; 9401553Srgrimes char *scsp; 9411553Srgrimes{ 9421553Srgrimes register char *strp; 9431553Srgrimes register nchrs, j; 9441553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 9451553Srgrimes int d, scnhgt; 9461553Srgrimes extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 9471553Srgrimes 9481553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 9491553Srgrimes strp = &outbuf[0]; 9501553Srgrimes sp = scsp; 9511553Srgrimes for (nchrs = 0; ; ) { 9521553Srgrimes d = dropit(c = TRC(cc = *sp++)); 9531553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 9541553Srgrimes for (j = WIDTH; --j;) 9551553Srgrimes *strp++ = BACKGND; 9561553Srgrimes else 9571553Srgrimes strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 9581553Srgrimes if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 9591553Srgrimes break; 9601553Srgrimes *strp++ = BACKGND; 9611553Srgrimes *strp++ = BACKGND; 9621553Srgrimes } 9631553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 9641553Srgrimes ; 9651553Srgrimes strp++; 9661553Srgrimes *strp++ = '\n'; 9671553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 9681553Srgrimes } 9691553Srgrimes} 9701553Srgrimes 9711553Srgrimesstatic int 9721553Srgrimesdropit(c) 9731553Srgrimes int c; 9741553Srgrimes{ 9751553Srgrimes switch(c) { 9761553Srgrimes 9771553Srgrimes case TRC('_'): 9781553Srgrimes case TRC(';'): 9791553Srgrimes case TRC(','): 9801553Srgrimes case TRC('g'): 9811553Srgrimes case TRC('j'): 9821553Srgrimes case TRC('p'): 9831553Srgrimes case TRC('q'): 9841553Srgrimes case TRC('y'): 9851553Srgrimes return (DROP); 9861553Srgrimes 9871553Srgrimes default: 9881553Srgrimes return (0); 9891553Srgrimes } 9901553Srgrimes} 9911553Srgrimes 9921553Srgrimes/* 9931553Srgrimes * sendmail --- 9941553Srgrimes * tell people about job completion 9951553Srgrimes */ 9961553Srgrimesstatic void 9971553Srgrimessendmail(user, bombed) 9981553Srgrimes char *user; 9991553Srgrimes int bombed; 10001553Srgrimes{ 10011553Srgrimes register int i; 10021553Srgrimes int p[2], s; 10031553Srgrimes register char *cp; 10041553Srgrimes char buf[100]; 10051553Srgrimes struct stat stb; 10061553Srgrimes FILE *fp; 10071553Srgrimes 10081553Srgrimes pipe(p); 10091553Srgrimes if ((s = dofork(DORETURN)) == 0) { /* child */ 10101553Srgrimes dup2(p[0], 0); 10111553Srgrimes for (i = 3; i < NOFILE; i++) 10121553Srgrimes (void) close(i); 10131553Srgrimes if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 10141553Srgrimes cp++; 10151553Srgrimes else 10161553Srgrimes cp = _PATH_SENDMAIL; 10171553Srgrimes sprintf(buf, "%s@%s", user, fromhost); 10181553Srgrimes execl(_PATH_SENDMAIL, cp, buf, 0); 10191553Srgrimes exit(0); 10201553Srgrimes } else if (s > 0) { /* parent */ 10211553Srgrimes dup2(p[1], 1); 10221553Srgrimes printf("To: %s@%s\n", user, fromhost); 10231553Srgrimes printf("Subject: printer job\n\n"); 10241553Srgrimes printf("Your printer job "); 10251553Srgrimes if (*jobname) 10261553Srgrimes printf("(%s) ", jobname); 10271553Srgrimes switch (bombed) { 10281553Srgrimes case OK: 10291553Srgrimes printf("\ncompleted successfully\n"); 10301553Srgrimes break; 10311553Srgrimes default: 10321553Srgrimes case FATALERR: 10331553Srgrimes printf("\ncould not be printed\n"); 10341553Srgrimes break; 10351553Srgrimes case NOACCT: 10361553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 10371553Srgrimes break; 10381553Srgrimes case FILTERERR: 10391553Srgrimes if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 10401553Srgrimes (fp = fopen(tempfile, "r")) == NULL) { 10411553Srgrimes printf("\nwas printed but had some errors\n"); 10421553Srgrimes break; 10431553Srgrimes } 10441553Srgrimes printf("\nwas printed but had the following errors:\n"); 10451553Srgrimes while ((i = getc(fp)) != EOF) 10461553Srgrimes putchar(i); 10471553Srgrimes (void) fclose(fp); 10481553Srgrimes break; 10491553Srgrimes case ACCESS: 10501553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 10511553Srgrimes } 10521553Srgrimes fflush(stdout); 10531553Srgrimes (void) close(1); 10541553Srgrimes } 10551553Srgrimes (void) close(p[0]); 10561553Srgrimes (void) close(p[1]); 10571553Srgrimes wait(&s); 10581553Srgrimes} 10591553Srgrimes 10601553Srgrimes/* 10611553Srgrimes * dofork - fork with retries on failure 10621553Srgrimes */ 10631553Srgrimesstatic int 10641553Srgrimesdofork(action) 10651553Srgrimes int action; 10661553Srgrimes{ 10671553Srgrimes register int i, pid; 10681553Srgrimes 10691553Srgrimes for (i = 0; i < 20; i++) { 10701553Srgrimes if ((pid = fork()) < 0) { 10711553Srgrimes sleep((unsigned)(i*i)); 10721553Srgrimes continue; 10731553Srgrimes } 10741553Srgrimes /* 10751553Srgrimes * Child should run as daemon instead of root 10761553Srgrimes */ 10771553Srgrimes if (pid == 0) 10781553Srgrimes setuid(DU); 10791553Srgrimes return(pid); 10801553Srgrimes } 10811553Srgrimes syslog(LOG_ERR, "can't fork"); 10821553Srgrimes 10831553Srgrimes switch (action) { 10841553Srgrimes case DORETURN: 10851553Srgrimes return (-1); 10861553Srgrimes default: 10871553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 10881553Srgrimes /*FALL THRU*/ 10891553Srgrimes case DOABORT: 10901553Srgrimes exit(1); 10911553Srgrimes } 10921553Srgrimes /*NOTREACHED*/ 10931553Srgrimes} 10941553Srgrimes 10951553Srgrimes/* 10961553Srgrimes * Kill child processes to abort current job. 10971553Srgrimes */ 10981553Srgrimesstatic void 10991553Srgrimesabortpr(signo) 11001553Srgrimes int signo; 11011553Srgrimes{ 11021553Srgrimes (void) unlink(tempfile); 11031553Srgrimes kill(0, SIGINT); 11041553Srgrimes if (ofilter > 0) 11051553Srgrimes kill(ofilter, SIGCONT); 11061553Srgrimes while (wait(NULL) > 0) 11071553Srgrimes ; 11081553Srgrimes exit(0); 11091553Srgrimes} 11101553Srgrimes 11111553Srgrimesstatic void 11121553Srgrimesinit() 11131553Srgrimes{ 11141553Srgrimes int status; 11151553Srgrimes char *s; 11161553Srgrimes 11171553Srgrimes if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 11181553Srgrimes syslog(LOG_ERR, "can't open printer description file"); 11191553Srgrimes exit(1); 11201553Srgrimes } else if (status == -1) { 11211553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 11221553Srgrimes exit(1); 11231553Srgrimes } else if (status == -3) 11241553Srgrimes fatal("potential reference loop detected in printcap file"); 11251553Srgrimes 11261553Srgrimes if (cgetstr(bp, "lp", &LP) == -1) 11271553Srgrimes LP = _PATH_DEFDEVLP; 11281553Srgrimes if (cgetstr(bp, "rp", &RP) == -1) 11291553Srgrimes RP = DEFLP; 11301553Srgrimes if (cgetstr(bp, "lo", &LO) == -1) 11311553Srgrimes LO = DEFLOCK; 11321553Srgrimes if (cgetstr(bp, "st", &ST) == -1) 11331553Srgrimes ST = DEFSTAT; 11341553Srgrimes if (cgetstr(bp, "lf", &LF) == -1) 11351553Srgrimes LF = _PATH_CONSOLE; 11361553Srgrimes if (cgetstr(bp, "sd", &SD) == -1) 11371553Srgrimes SD = _PATH_DEFSPOOL; 11381553Srgrimes if (cgetnum(bp, "du", &DU) < 0) 11391553Srgrimes DU = DEFUID; 11401553Srgrimes if (cgetstr(bp,"ff", &FF) == -1) 11411553Srgrimes FF = DEFFF; 11421553Srgrimes if (cgetnum(bp, "pw", &PW) < 0) 11431553Srgrimes PW = DEFWIDTH; 11441553Srgrimes sprintf(&width[2], "%d", PW); 11451553Srgrimes if (cgetnum(bp, "pl", &PL) < 0) 11461553Srgrimes PL = DEFLENGTH; 11471553Srgrimes sprintf(&length[2], "%d", PL); 11481553Srgrimes if (cgetnum(bp,"px", &PX) < 0) 11491553Srgrimes PX = 0; 11501553Srgrimes sprintf(&pxwidth[2], "%d", PX); 11511553Srgrimes if (cgetnum(bp, "py", &PY) < 0) 11521553Srgrimes PY = 0; 11531553Srgrimes sprintf(&pxlength[2], "%d", PY); 11541553Srgrimes cgetstr(bp, "rm", &RM); 11551553Srgrimes if (s = checkremote()) 11561553Srgrimes syslog(LOG_WARNING, s); 11571553Srgrimes 11581553Srgrimes cgetstr(bp, "af", &AF); 11591553Srgrimes cgetstr(bp, "of", &OF); 11601553Srgrimes cgetstr(bp, "if", &IF); 11611553Srgrimes cgetstr(bp, "rf", &RF); 11621553Srgrimes cgetstr(bp, "tf", &TF); 11631553Srgrimes cgetstr(bp, "nf", &NF); 11641553Srgrimes cgetstr(bp, "df", &DF); 11651553Srgrimes cgetstr(bp, "gf", &GF); 11661553Srgrimes cgetstr(bp, "vf", &VF); 11671553Srgrimes cgetstr(bp, "cf", &CF); 11681553Srgrimes cgetstr(bp, "tr", &TR); 11691553Srgrimes 11701553Srgrimes RS = (cgetcap(bp, "rs", ':') != NULL); 11711553Srgrimes SF = (cgetcap(bp, "sf", ':') != NULL); 11721553Srgrimes SH = (cgetcap(bp, "sh", ':') != NULL); 11731553Srgrimes SB = (cgetcap(bp, "sb", ':') != NULL); 11741553Srgrimes HL = (cgetcap(bp, "hl", ':') != NULL); 11751553Srgrimes RW = (cgetcap(bp, "rw", ':') != NULL); 11761553Srgrimes 11771553Srgrimes cgetnum(bp, "br", &BR); 11781553Srgrimes if (cgetnum(bp, "fc", &FC) < 0) 11791553Srgrimes FC = 0; 11801553Srgrimes if (cgetnum(bp, "fs", &FS) < 0) 11811553Srgrimes FS = 0; 11821553Srgrimes if (cgetnum(bp, "xc", &XC) < 0) 11831553Srgrimes XC = 0; 11841553Srgrimes if (cgetnum(bp, "xs", &XS) < 0) 11851553Srgrimes XS = 0; 11861553Srgrimes 11871553Srgrimes tof = (cgetcap(bp, "fo", ':') == NULL); 11881553Srgrimes} 11891553Srgrimes 11901553Srgrimes/* 11911553Srgrimes * Acquire line printer or remote connection. 11921553Srgrimes */ 11931553Srgrimesstatic void 11941553Srgrimesopenpr() 11951553Srgrimes{ 11961553Srgrimes register int i, n; 11971553Srgrimes int resp; 11981553Srgrimes 11991553Srgrimes if (!sendtorem && *LP) { 12001553Srgrimes for (i = 1; ; i = i < 32 ? i << 1 : i) { 12011553Srgrimes pfd = open(LP, RW ? O_RDWR : O_WRONLY); 12021553Srgrimes if (pfd >= 0) 12031553Srgrimes break; 12041553Srgrimes if (errno == ENOENT) { 12051553Srgrimes syslog(LOG_ERR, "%s: %m", LP); 12061553Srgrimes exit(1); 12071553Srgrimes } 12081553Srgrimes if (i == 1) 12091553Srgrimes pstatus("waiting for %s to become ready (offline ?)", printer); 12101553Srgrimes sleep(i); 12111553Srgrimes } 12121553Srgrimes if (isatty(pfd)) 12131553Srgrimes setty(); 12141553Srgrimes pstatus("%s is ready and printing", printer); 12151553Srgrimes } else if (RM != NULL) { 12161553Srgrimes for (i = 1; ; i = i < 256 ? i << 1 : i) { 12171553Srgrimes resp = -1; 12181553Srgrimes pfd = getport(RM); 12191553Srgrimes if (pfd >= 0) { 12201553Srgrimes (void) sprintf(line, "\2%s\n", RP); 12211553Srgrimes n = strlen(line); 12221553Srgrimes if (write(pfd, line, n) == n && 12231553Srgrimes (resp = response()) == '\0') 12241553Srgrimes break; 12251553Srgrimes (void) close(pfd); 12261553Srgrimes } 12271553Srgrimes if (i == 1) { 12281553Srgrimes if (resp < 0) 12291553Srgrimes pstatus("waiting for %s to come up", RM); 12301553Srgrimes else { 12311553Srgrimes pstatus("waiting for queue to be enabled on %s", RM); 12321553Srgrimes i = 256; 12331553Srgrimes } 12341553Srgrimes } 12351553Srgrimes sleep(i); 12361553Srgrimes } 12371553Srgrimes pstatus("sending to %s", RM); 12381553Srgrimes remote = 1; 12391553Srgrimes } else { 12401553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 12411553Srgrimes printer); 12421553Srgrimes exit(1); 12431553Srgrimes } 12441553Srgrimes /* 12451553Srgrimes * Start up an output filter, if needed. 12461553Srgrimes */ 12471553Srgrimes if (!remote && OF) { 12481553Srgrimes int p[2]; 12491553Srgrimes char *cp; 12501553Srgrimes 12511553Srgrimes pipe(p); 12521553Srgrimes if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 12531553Srgrimes dup2(p[0], 0); /* pipe is std in */ 12541553Srgrimes dup2(pfd, 1); /* printer is std out */ 12551553Srgrimes for (i = 3; i < NOFILE; i++) 12561553Srgrimes (void) close(i); 12571553Srgrimes if ((cp = rindex(OF, '/')) == NULL) 12581553Srgrimes cp = OF; 12591553Srgrimes else 12601553Srgrimes cp++; 12611553Srgrimes execl(OF, cp, width, length, 0); 12621553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, OF); 12631553Srgrimes exit(1); 12641553Srgrimes } 12651553Srgrimes (void) close(p[0]); /* close input side */ 12661553Srgrimes ofd = p[1]; /* use pipe for output */ 12671553Srgrimes } else { 12681553Srgrimes ofd = pfd; 12691553Srgrimes ofilter = 0; 12701553Srgrimes } 12711553Srgrimes} 12721553Srgrimes 12731553Srgrimesstruct bauds { 12741553Srgrimes int baud; 12751553Srgrimes int speed; 12761553Srgrimes} bauds[] = { 12771553Srgrimes 50, B50, 12781553Srgrimes 75, B75, 12791553Srgrimes 110, B110, 12801553Srgrimes 134, B134, 12811553Srgrimes 150, B150, 12821553Srgrimes 200, B200, 12831553Srgrimes 300, B300, 12841553Srgrimes 600, B600, 12851553Srgrimes 1200, B1200, 12861553Srgrimes 1800, B1800, 12871553Srgrimes 2400, B2400, 12881553Srgrimes 4800, B4800, 12891553Srgrimes 9600, B9600, 12901553Srgrimes 19200, EXTA, 12911553Srgrimes 38400, EXTB, 12921553Srgrimes 0, 0 12931553Srgrimes}; 12941553Srgrimes 12951553Srgrimes/* 12961553Srgrimes * setup tty lines. 12971553Srgrimes */ 12981553Srgrimesstatic void 12991553Srgrimessetty() 13001553Srgrimes{ 13011553Srgrimes struct sgttyb ttybuf; 13021553Srgrimes register struct bauds *bp; 13031553Srgrimes 13041553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 13051553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 13061553Srgrimes exit(1); 13071553Srgrimes } 13081553Srgrimes if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 13091553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 13101553Srgrimes exit(1); 13111553Srgrimes } 13121553Srgrimes if (BR > 0) { 13131553Srgrimes for (bp = bauds; bp->baud; bp++) 13141553Srgrimes if (BR == bp->baud) 13151553Srgrimes break; 13161553Srgrimes if (!bp->baud) { 13171553Srgrimes syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 13181553Srgrimes exit(1); 13191553Srgrimes } 13201553Srgrimes ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 13211553Srgrimes } 13221553Srgrimes ttybuf.sg_flags &= ~FC; 13231553Srgrimes ttybuf.sg_flags |= FS; 13241553Srgrimes if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 13251553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 13261553Srgrimes exit(1); 13271553Srgrimes } 13281553Srgrimes if (XC) { 13291553Srgrimes if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 13301553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 13311553Srgrimes exit(1); 13321553Srgrimes } 13331553Srgrimes } 13341553Srgrimes if (XS) { 13351553Srgrimes if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 13361553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 13371553Srgrimes exit(1); 13381553Srgrimes } 13391553Srgrimes } 13401553Srgrimes} 13411553Srgrimes 13421553Srgrimes#if __STDC__ 13431553Srgrimes#include <stdarg.h> 13441553Srgrimes#else 13451553Srgrimes#include <varargs.h> 13461553Srgrimes#endif 13471553Srgrimes 13481553Srgrimesvoid 13491553Srgrimes#if __STDC__ 13501553Srgrimespstatus(const char *msg, ...) 13511553Srgrimes#else 13521553Srgrimespstatus(msg, va_alist) 13531553Srgrimes char *msg; 13541553Srgrimes va_dcl 13551553Srgrimes#endif 13561553Srgrimes{ 13571553Srgrimes register int fd; 13581553Srgrimes char buf[BUFSIZ]; 13591553Srgrimes va_list ap; 13601553Srgrimes#if __STDC__ 13611553Srgrimes va_start(ap, msg); 13621553Srgrimes#else 13631553Srgrimes va_start(ap); 13641553Srgrimes#endif 13651553Srgrimes 13661553Srgrimes umask(0); 13671553Srgrimes fd = open(ST, O_WRONLY|O_CREAT, 0664); 13681553Srgrimes if (fd < 0 || flock(fd, LOCK_EX) < 0) { 13691553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, ST); 13701553Srgrimes exit(1); 13711553Srgrimes } 13721553Srgrimes ftruncate(fd, 0); 13731553Srgrimes (void)vsnprintf(buf, sizeof(buf), msg, ap); 13741553Srgrimes va_end(ap); 13751553Srgrimes strcat(buf, "\n"); 13761553Srgrimes (void) write(fd, buf, strlen(buf)); 13771553Srgrimes (void) close(fd); 13781553Srgrimes} 1379