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