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