printjob.c revision 30407
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * 61553Srgrimes * Redistribution and use in source and binary forms, with or without 71553Srgrimes * modification, are permitted provided that the following conditions 81553Srgrimes * are met: 91553Srgrimes * 1. Redistributions of source code must retain the above copyright 101553Srgrimes * notice, this list of conditions and the following disclaimer. 111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121553Srgrimes * notice, this list of conditions and the following disclaimer in the 131553Srgrimes * documentation and/or other materials provided with the distribution. 141553Srgrimes * 3. All advertising materials mentioning features or use of this software 151553Srgrimes * must display the following acknowledgement: 161553Srgrimes * This product includes software developed by the University of 171553Srgrimes * California, Berkeley and its contributors. 181553Srgrimes * 4. Neither the name of the University nor the names of its contributors 191553Srgrimes * may be used to endorse or promote products derived from this software 201553Srgrimes * without specific prior written permission. 211553Srgrimes * 221553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321553Srgrimes * SUCH DAMAGE. 331553Srgrimes */ 341553Srgrimes 351553Srgrimes#ifndef lint 361553Srgrimesstatic char copyright[] = 371553Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 381553Srgrimes The Regents of the University of California. All rights reserved.\n"; 391553Srgrimes#endif /* not lint */ 401553Srgrimes 411553Srgrimes#ifndef lint 4215648Sjoergstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 431553Srgrimes#endif /* not lint */ 441553Srgrimes 451553Srgrimes 461553Srgrimes/* 471553Srgrimes * printjob -- print jobs in the queue. 481553Srgrimes * 491553Srgrimes * NOTE: the lock file is used to pass information to lpq and lprm. 501553Srgrimes * it does not need to be removed because file locks are dynamic. 511553Srgrimes */ 521553Srgrimes 531553Srgrimes#include <sys/param.h> 541553Srgrimes#include <sys/wait.h> 551553Srgrimes#include <sys/stat.h> 561553Srgrimes#include <sys/types.h> 571553Srgrimes 581553Srgrimes#include <pwd.h> 591553Srgrimes#include <unistd.h> 601553Srgrimes#include <signal.h> 611553Srgrimes#include <syslog.h> 621553Srgrimes#include <fcntl.h> 631553Srgrimes#include <dirent.h> 641553Srgrimes#include <errno.h> 651553Srgrimes#include <stdio.h> 661553Srgrimes#include <string.h> 671553Srgrimes#include <stdlib.h> 6815032Ssef#include <sys/ioctl.h> 6915032Ssef#include <termios.h> 7015703Sjoerg#include <time.h> 711553Srgrimes#include "lp.h" 721553Srgrimes#include "lp.local.h" 731553Srgrimes#include "pathnames.h" 741553Srgrimes#include "extern.h" 751553Srgrimes 761553Srgrimes#define DORETURN 0 /* absorb fork error */ 771553Srgrimes#define DOABORT 1 /* abort if dofork fails */ 781553Srgrimes 791553Srgrimes/* 801553Srgrimes * Error tokens 811553Srgrimes */ 821553Srgrimes#define REPRINT -2 831553Srgrimes#define ERROR -1 841553Srgrimes#define OK 0 851553Srgrimes#define FATALERR 1 861553Srgrimes#define NOACCT 2 871553Srgrimes#define FILTERERR 3 881553Srgrimes#define ACCESS 4 891553Srgrimes 901553Srgrimesstatic dev_t fdev; /* device of file pointed to by symlink */ 911553Srgrimesstatic ino_t fino; /* inode of file pointed to by symlink */ 921553Srgrimesstatic FILE *cfp; /* control file */ 931553Srgrimesstatic int child; /* id of any filters */ 941553Srgrimesstatic int lfd; /* lock file descriptor */ 951553Srgrimesstatic int ofd; /* output filter file descriptor */ 961553Srgrimesstatic int ofilter; /* id of output filter, if any */ 9724831Sbrianstatic int tfd = -1; /* output filter temp file output */ 981553Srgrimesstatic int pfd; /* prstatic inter file descriptor */ 991553Srgrimesstatic int pid; /* pid of lpd process */ 1001553Srgrimesstatic int prchild; /* id of pr process */ 1011553Srgrimesstatic char title[80]; /* ``pr'' title */ 1021553Srgrimesstatic int tof; /* true if at top of form */ 1031553Srgrimes 1041553Srgrimesstatic char class[32]; /* classification field */ 1051553Srgrimesstatic char fromhost[32]; /* user's host machine */ 1061553Srgrimes /* indentation size in static characters */ 1078857Srgrimesstatic char indent[10] = "-i0"; 1081553Srgrimesstatic char jobname[100]; /* job or file name */ 1091553Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1101553Srgrimesstatic char logname[32]; /* user's login name */ 1111553Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1121553Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 11324831Sbrianstatic char tempfile[] = "errsXXXXXX"; /* file name for filter errors */ 1141553Srgrimesstatic char width[10] = "-w"; /* page width in static characters */ 11524831Sbrian#define TFILENAME "fltXXXXXX" 11624831Sbrianstatic char tfile[] = TFILENAME; /* file name for filter output */ 1171553Srgrimes 1181553Srgrimesstatic void abortpr __P((int)); 11930407Sjoergstatic void alarmhandler __P((int)); 1201553Srgrimesstatic void banner __P((char *, char *)); 1211553Srgrimesstatic int dofork __P((int)); 1221553Srgrimesstatic int dropit __P((int)); 1231553Srgrimesstatic void init __P((void)); 1241553Srgrimesstatic void openpr __P((void)); 12515648Sjoergstatic void opennet __P((char *)); 12615648Sjoergstatic void opentty __P((void)); 12715648Sjoergstatic void openrem __P((void)); 1281553Srgrimesstatic int print __P((int, char *)); 1291553Srgrimesstatic int printit __P((char *)); 1301553Srgrimesstatic void pstatus __P((const char *, ...)); 1311553Srgrimesstatic char response __P((void)); 1321553Srgrimesstatic void scan_out __P((int, char *, int)); 1331553Srgrimesstatic char *scnline __P((int, char *, int)); 13424831Sbrianstatic int sendfile __P((int, char *, char)); 1351553Srgrimesstatic int sendit __P((char *)); 1361553Srgrimesstatic void sendmail __P((char *, int)); 1371553Srgrimesstatic void setty __P((void)); 1381553Srgrimes 1391553Srgrimesvoid 1401553Srgrimesprintjob() 1411553Srgrimes{ 1421553Srgrimes struct stat stb; 1431553Srgrimes register struct queue *q, **qp; 1441553Srgrimes struct queue **queue; 1451553Srgrimes register int i, nitems; 14615648Sjoerg off_t pidoff; 14715648Sjoerg int errcnt, count = 0; 1481553Srgrimes 1491553Srgrimes init(); /* set up capabilities */ 1501553Srgrimes (void) write(1, "", 1); /* ack that daemon is started */ 1511553Srgrimes (void) close(2); /* set up log file */ 1521553Srgrimes if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 1531553Srgrimes syslog(LOG_ERR, "%s: %m", LF); 1541553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1551553Srgrimes } 1561553Srgrimes setgid(getegid()); 1571553Srgrimes pid = getpid(); /* for use with lprm */ 1581553Srgrimes setpgrp(0, pid); 1591553Srgrimes signal(SIGHUP, abortpr); 1601553Srgrimes signal(SIGINT, abortpr); 1611553Srgrimes signal(SIGQUIT, abortpr); 1621553Srgrimes signal(SIGTERM, abortpr); 1631553Srgrimes 1641553Srgrimes (void) mktemp(tempfile); 1651553Srgrimes 1661553Srgrimes /* 1671553Srgrimes * uses short form file names 1681553Srgrimes */ 1691553Srgrimes if (chdir(SD) < 0) { 1701553Srgrimes syslog(LOG_ERR, "%s: %m", SD); 1711553Srgrimes exit(1); 1721553Srgrimes } 1731553Srgrimes if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 1741553Srgrimes exit(0); /* printing disabled */ 1751553Srgrimes lfd = open(LO, O_WRONLY|O_CREAT, 0644); 1761553Srgrimes if (lfd < 0) { 1771553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1781553Srgrimes exit(1); 1791553Srgrimes } 1801553Srgrimes if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 1811553Srgrimes if (errno == EWOULDBLOCK) /* active deamon present */ 1821553Srgrimes exit(0); 1831553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1841553Srgrimes exit(1); 1851553Srgrimes } 1861553Srgrimes ftruncate(lfd, 0); 1871553Srgrimes /* 1881553Srgrimes * write process id for others to know 1891553Srgrimes */ 1901553Srgrimes sprintf(line, "%u\n", pid); 1911553Srgrimes pidoff = i = strlen(line); 1921553Srgrimes if (write(lfd, line, i) != i) { 1931553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1941553Srgrimes exit(1); 1951553Srgrimes } 1961553Srgrimes /* 1971553Srgrimes * search the spool directory for work and sort by queue order. 1981553Srgrimes */ 1991553Srgrimes if ((nitems = getq(&queue)) < 0) { 2001553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 2011553Srgrimes exit(1); 2021553Srgrimes } 2031553Srgrimes if (nitems == 0) /* no work to do */ 2041553Srgrimes exit(0); 2051553Srgrimes if (stb.st_mode & 01) { /* reset queue flag */ 2061553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2071553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2081553Srgrimes } 2091553Srgrimes openpr(); /* open printer or remote */ 2101553Srgrimesagain: 2111553Srgrimes /* 2121553Srgrimes * we found something to do now do it -- 2131553Srgrimes * write the name of the current control file into the lock file 2141553Srgrimes * so the spool queue program can tell what we're working on 2151553Srgrimes */ 2161553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2171553Srgrimes q = *qp++; 2181553Srgrimes if (stat(q->q_name, &stb) < 0) 2191553Srgrimes continue; 22015648Sjoerg errcnt = 0; 2211553Srgrimes restart: 22215648Sjoerg (void) lseek(lfd, pidoff, 0); 22327748Simp (void) snprintf(line, sizeof(line), "%s\n", q->q_name); 2241553Srgrimes i = strlen(line); 2251553Srgrimes if (write(lfd, line, i) != i) 2261553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2271553Srgrimes if (!remote) 2281553Srgrimes i = printit(q->q_name); 2291553Srgrimes else 2301553Srgrimes i = sendit(q->q_name); 2311553Srgrimes /* 2321553Srgrimes * Check to see if we are supposed to stop printing or 2331553Srgrimes * if we are to rebuild the queue. 2341553Srgrimes */ 2351553Srgrimes if (fstat(lfd, &stb) == 0) { 2361553Srgrimes /* stop printing before starting next job? */ 2371553Srgrimes if (stb.st_mode & 0100) 2381553Srgrimes goto done; 2391553Srgrimes /* rebuild queue (after lpc topq) */ 2401553Srgrimes if (stb.st_mode & 01) { 2411553Srgrimes for (free((char *) q); nitems--; free((char *) q)) 2421553Srgrimes q = *qp++; 2431553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2441553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 2451553Srgrimes printer, LO); 2461553Srgrimes break; 2471553Srgrimes } 2481553Srgrimes } 2491553Srgrimes if (i == OK) /* file ok and printed */ 2501553Srgrimes count++; 25115648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 25215648Sjoerg /* try reprinting the job */ 2531553Srgrimes syslog(LOG_INFO, "restarting %s", printer); 2541553Srgrimes if (ofilter > 0) { 2551553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2561553Srgrimes (void) close(ofd); 25715648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2581553Srgrimes ; 2591553Srgrimes ofilter = 0; 2601553Srgrimes } 2611553Srgrimes (void) close(pfd); /* close printer */ 2621553Srgrimes if (ftruncate(lfd, pidoff) < 0) 2631553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 2641553Srgrimes openpr(); /* try to reopen printer */ 2651553Srgrimes goto restart; 26615648Sjoerg } else { 26715648Sjoerg syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 26815648Sjoerg remote ? "sent to remote host" : "printed", q->q_name); 26915648Sjoerg if (i == REPRINT) { 27027748Simp /* ensure we don't attempt this job again */ 27115648Sjoerg (void) unlink(q->q_name); 27215648Sjoerg q->q_name[0] = 'd'; 27315648Sjoerg (void) unlink(q->q_name); 27415648Sjoerg if (logname[0]) 27515648Sjoerg sendmail(logname, FATALERR); 27615648Sjoerg } 2771553Srgrimes } 2781553Srgrimes } 2791553Srgrimes free((char *) queue); 2801553Srgrimes /* 2811553Srgrimes * search the spool directory for more work. 2821553Srgrimes */ 2831553Srgrimes if ((nitems = getq(&queue)) < 0) { 2841553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 2851553Srgrimes exit(1); 2861553Srgrimes } 2871553Srgrimes if (nitems == 0) { /* no more work to do */ 2881553Srgrimes done: 2891553Srgrimes if (count > 0) { /* Files actually printed */ 2901553Srgrimes if (!SF && !tof) 2911553Srgrimes (void) write(ofd, FF, strlen(FF)); 2921553Srgrimes if (TR != NULL) /* output trailer */ 2931553Srgrimes (void) write(ofd, TR, strlen(TR)); 2941553Srgrimes } 29519202Simp (void) close(ofd); 29619202Simp (void) wait(NULL); 2971553Srgrimes (void) unlink(tempfile); 2981553Srgrimes exit(0); 2991553Srgrimes } 3001553Srgrimes goto again; 3011553Srgrimes} 3021553Srgrimes 3031553Srgrimeschar fonts[4][50]; /* fonts for troff */ 3041553Srgrimes 3051553Srgrimeschar ifonts[4][40] = { 3061553Srgrimes _PATH_VFONTR, 3071553Srgrimes _PATH_VFONTI, 3081553Srgrimes _PATH_VFONTB, 3091553Srgrimes _PATH_VFONTS, 3101553Srgrimes}; 3111553Srgrimes 3121553Srgrimes/* 3131553Srgrimes * The remaining part is the reading of the control file (cf) 3141553Srgrimes * and performing the various actions. 3151553Srgrimes */ 3161553Srgrimesstatic int 3171553Srgrimesprintit(file) 3181553Srgrimes char *file; 3191553Srgrimes{ 3201553Srgrimes register int i; 3211553Srgrimes char *cp; 3221553Srgrimes int bombed = OK; 3231553Srgrimes 3241553Srgrimes /* 3251553Srgrimes * open control file; ignore if no longer there. 3261553Srgrimes */ 3271553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 3281553Srgrimes syslog(LOG_INFO, "%s: %s: %m", printer, file); 3291553Srgrimes return(OK); 3301553Srgrimes } 3311553Srgrimes /* 3321553Srgrimes * Reset troff fonts. 3331553Srgrimes */ 3341553Srgrimes for (i = 0; i < 4; i++) 3351553Srgrimes strcpy(fonts[i], ifonts[i]); 33627748Simp sprintf(&width[2], "%ld", PW); 3371553Srgrimes strcpy(indent+2, "0"); 3381553Srgrimes 3391553Srgrimes /* 3401553Srgrimes * read the control file for work to do 3411553Srgrimes * 3421553Srgrimes * file format -- first character in the line is a command 3431553Srgrimes * rest of the line is the argument. 3441553Srgrimes * valid commands are: 3451553Srgrimes * 3461553Srgrimes * S -- "stat info" for symbolic link protection 3471553Srgrimes * J -- "job name" on banner page 3481553Srgrimes * C -- "class name" on banner page 3491553Srgrimes * L -- "literal" user's name to print on banner 3501553Srgrimes * T -- "title" for pr 3511553Srgrimes * H -- "host name" of machine where lpr was done 3521553Srgrimes * P -- "person" user's login name 3531553Srgrimes * I -- "indent" amount to indent output 35415648Sjoerg * R -- laser dpi "resolution" 3551553Srgrimes * f -- "file name" name of text file to print 3561553Srgrimes * l -- "file name" text file with control chars 3571553Srgrimes * p -- "file name" text file to print with pr(1) 3581553Srgrimes * t -- "file name" troff(1) file to print 3591553Srgrimes * n -- "file name" ditroff(1) file to print 3601553Srgrimes * d -- "file name" dvi file to print 3611553Srgrimes * g -- "file name" plot(1G) file to print 3621553Srgrimes * v -- "file name" plain raster file to print 3631553Srgrimes * c -- "file name" cifplot file to print 3641553Srgrimes * 1 -- "R font file" for troff 3651553Srgrimes * 2 -- "I font file" for troff 3661553Srgrimes * 3 -- "B font file" for troff 3671553Srgrimes * 4 -- "S font file" for troff 3681553Srgrimes * N -- "name" of file (used by lpq) 3691553Srgrimes * U -- "unlink" name of file to remove 3701553Srgrimes * (after we print it. (Pass 2 only)). 3711553Srgrimes * M -- "mail" to user when done printing 3721553Srgrimes * 3731553Srgrimes * getline reads a line and expands tabs to blanks 3741553Srgrimes */ 3751553Srgrimes 3761553Srgrimes /* pass 1 */ 3771553Srgrimes 3781553Srgrimes while (getline(cfp)) 3791553Srgrimes switch (line[0]) { 3801553Srgrimes case 'H': 38127748Simp strncpy(fromhost, line+1, sizeof(fromhost) - 1); 38227748Simp fromhost[sizeof(fromhost) - 1] = '\0'; 38327748Simp if (class[0] == '\0') { 38427748Simp strncpy(class, line+1, sizeof(class) - 1); 38527748Simp class[sizeof(class) - 1] = '\0'; 38627748Simp } 3871553Srgrimes continue; 3881553Srgrimes 3891553Srgrimes case 'P': 39027748Simp strncpy(logname, line+1, sizeof(logname) - 1); 39127748Simp logname[sizeof(logname) - 1] = '\0'; 3921553Srgrimes if (RS) { /* restricted */ 3931553Srgrimes if (getpwnam(logname) == NULL) { 3941553Srgrimes bombed = NOACCT; 3951553Srgrimes sendmail(line+1, bombed); 3961553Srgrimes goto pass2; 3971553Srgrimes } 3981553Srgrimes } 3991553Srgrimes continue; 4001553Srgrimes 4011553Srgrimes case 'S': 4021553Srgrimes cp = line+1; 4031553Srgrimes i = 0; 4041553Srgrimes while (*cp >= '0' && *cp <= '9') 4051553Srgrimes i = i * 10 + (*cp++ - '0'); 4061553Srgrimes fdev = i; 4071553Srgrimes cp++; 4081553Srgrimes i = 0; 4091553Srgrimes while (*cp >= '0' && *cp <= '9') 4101553Srgrimes i = i * 10 + (*cp++ - '0'); 4111553Srgrimes fino = i; 4121553Srgrimes continue; 4131553Srgrimes 4141553Srgrimes case 'J': 41527748Simp if (line[1] != '\0') { 41627748Simp strncpy(jobname, line+1, sizeof(jobname) - 1); 41727748Simp jobname[sizeof(jobname) - 1] = '\0'; 41827748Simp } else 4191553Srgrimes strcpy(jobname, " "); 4201553Srgrimes continue; 4211553Srgrimes 4221553Srgrimes case 'C': 4231553Srgrimes if (line[1] != '\0') 42427748Simp strncpy(class, line+1, sizeof(class) - 1); 4251553Srgrimes else if (class[0] == '\0') 4261553Srgrimes gethostname(class, sizeof(class)); 42727748Simp class[sizeof(class) - 1] = '\0'; 4281553Srgrimes continue; 4291553Srgrimes 4301553Srgrimes case 'T': /* header title for pr */ 43127748Simp strncpy(title, line+1, sizeof(title) - 1); 43227748Simp title[sizeof(title) - 1] = '\0'; 4331553Srgrimes continue; 4341553Srgrimes 4351553Srgrimes case 'L': /* identification line */ 4361553Srgrimes if (!SH && !HL) 4371553Srgrimes banner(line+1, jobname); 4381553Srgrimes continue; 4391553Srgrimes 4401553Srgrimes case '1': /* troff fonts */ 4411553Srgrimes case '2': 4421553Srgrimes case '3': 4431553Srgrimes case '4': 44427748Simp if (line[1] != '\0') { 44527748Simp strncpy(fonts[line[0]-'1'], line+1, 44627748Simp 50-1); 44727748Simp fonts[line[0]-'1'][50-1] = '\0'; 44827748Simp } 4491553Srgrimes continue; 4501553Srgrimes 4511553Srgrimes case 'W': /* page width */ 45227748Simp strncpy(width+2, line+1, sizeof(width) - 3); 45327748Simp width[2+sizeof(width) - 3] = '\0'; 4541553Srgrimes continue; 4551553Srgrimes 4561553Srgrimes case 'I': /* indent amount */ 45727748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 45827748Simp indent[2+sizeof(indent) - 3] = '\0'; 4591553Srgrimes continue; 4601553Srgrimes 4611553Srgrimes default: /* some file to print */ 4621553Srgrimes switch (i = print(line[0], line+1)) { 4631553Srgrimes case ERROR: 4641553Srgrimes if (bombed == OK) 4651553Srgrimes bombed = FATALERR; 4661553Srgrimes break; 4671553Srgrimes case REPRINT: 4681553Srgrimes (void) fclose(cfp); 4691553Srgrimes return(REPRINT); 4701553Srgrimes case FILTERERR: 4711553Srgrimes case ACCESS: 4721553Srgrimes bombed = i; 4731553Srgrimes sendmail(logname, bombed); 4741553Srgrimes } 4751553Srgrimes title[0] = '\0'; 4761553Srgrimes continue; 4771553Srgrimes 4781553Srgrimes case 'N': 4791553Srgrimes case 'U': 4801553Srgrimes case 'M': 48115648Sjoerg case 'R': 4821553Srgrimes continue; 4831553Srgrimes } 4841553Srgrimes 4851553Srgrimes /* pass 2 */ 4861553Srgrimes 4871553Srgrimespass2: 4881553Srgrimes fseek(cfp, 0L, 0); 4891553Srgrimes while (getline(cfp)) 4901553Srgrimes switch (line[0]) { 4911553Srgrimes case 'L': /* identification line */ 4921553Srgrimes if (!SH && HL) 4931553Srgrimes banner(line+1, jobname); 4941553Srgrimes continue; 4951553Srgrimes 4961553Srgrimes case 'M': 4971553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 4981553Srgrimes sendmail(line+1, bombed); 4991553Srgrimes continue; 5001553Srgrimes 5011553Srgrimes case 'U': 50227748Simp if (strchr(line+1, '/')) 50327748Simp continue; 5041553Srgrimes (void) unlink(line+1); 5051553Srgrimes } 5061553Srgrimes /* 5071553Srgrimes * clean-up in case another control file exists 5081553Srgrimes */ 5091553Srgrimes (void) fclose(cfp); 5101553Srgrimes (void) unlink(file); 5111553Srgrimes return(bombed == OK ? OK : ERROR); 5121553Srgrimes} 5131553Srgrimes 5141553Srgrimes/* 5151553Srgrimes * Print a file. 5161553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 5171553Srgrimes * Return -1 if a non-recoverable error occured, 5181553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 5191553Srgrimes * 1 if we should try to reprint this job and 5201553Srgrimes * 0 if all is well. 5211553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5221553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5231553Srgrimes */ 5241553Srgrimesstatic int 5251553Srgrimesprint(format, file) 5261553Srgrimes int format; 5271553Srgrimes char *file; 5281553Srgrimes{ 5291553Srgrimes register int n; 5301553Srgrimes register char *prog; 53118569Sbde int dtablesize, fi, fo; 5321553Srgrimes FILE *fp; 5331553Srgrimes char *av[15], buf[BUFSIZ]; 5341553Srgrimes int pid, p[2], stopped = 0; 5351553Srgrimes union wait status; 5361553Srgrimes struct stat stb; 5371553Srgrimes 5381553Srgrimes if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 5391553Srgrimes return(ERROR); 5401553Srgrimes /* 5411553Srgrimes * Check to see if data file is a symbolic link. If so, it should 5421553Srgrimes * still point to the same file or someone is trying to print 5431553Srgrimes * something he shouldn't. 5441553Srgrimes */ 5451553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 5461553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 5471553Srgrimes return(ACCESS); 5481553Srgrimes if (!SF && !tof) { /* start on a fresh page */ 5491553Srgrimes (void) write(ofd, FF, strlen(FF)); 5501553Srgrimes tof = 1; 5511553Srgrimes } 5521553Srgrimes if (IF == NULL && (format == 'f' || format == 'l')) { 5531553Srgrimes tof = 0; 5541553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 5551553Srgrimes if (write(ofd, buf, n) != n) { 5561553Srgrimes (void) close(fi); 5571553Srgrimes return(REPRINT); 5581553Srgrimes } 5591553Srgrimes (void) close(fi); 5601553Srgrimes return(OK); 5611553Srgrimes } 5621553Srgrimes switch (format) { 5631553Srgrimes case 'p': /* print file using 'pr' */ 5641553Srgrimes if (IF == NULL) { /* use output filter */ 5651553Srgrimes prog = _PATH_PR; 5661553Srgrimes av[0] = "pr"; 5671553Srgrimes av[1] = width; 5681553Srgrimes av[2] = length; 5691553Srgrimes av[3] = "-h"; 5701553Srgrimes av[4] = *title ? title : " "; 5715445Sjoerg av[5] = "-F"; 5725445Sjoerg av[6] = 0; 5731553Srgrimes fo = ofd; 5741553Srgrimes goto start; 5751553Srgrimes } 5761553Srgrimes pipe(p); 5771553Srgrimes if ((prchild = dofork(DORETURN)) == 0) { /* child */ 5781553Srgrimes dup2(fi, 0); /* file is stdin */ 5791553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 5808094Sjkh closelog(); 58118569Sbde for (n = 3, dtablesize = getdtablesize(); 58218569Sbde n < dtablesize; n++) 5831553Srgrimes (void) close(n); 5841553Srgrimes execl(_PATH_PR, "pr", width, length, 5855445Sjoerg "-h", *title ? title : " ", "-F", 0); 5861553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 5871553Srgrimes exit(2); 5881553Srgrimes } 5891553Srgrimes (void) close(p[1]); /* close output side */ 5901553Srgrimes (void) close(fi); 5911553Srgrimes if (prchild < 0) { 5921553Srgrimes prchild = 0; 5931553Srgrimes (void) close(p[0]); 5941553Srgrimes return(ERROR); 5951553Srgrimes } 5961553Srgrimes fi = p[0]; /* use pipe for input */ 5971553Srgrimes case 'f': /* print plain text file */ 5981553Srgrimes prog = IF; 5991553Srgrimes av[1] = width; 6001553Srgrimes av[2] = length; 6011553Srgrimes av[3] = indent; 6021553Srgrimes n = 4; 6031553Srgrimes break; 6041553Srgrimes case 'l': /* like 'f' but pass control characters */ 6051553Srgrimes prog = IF; 6061553Srgrimes av[1] = "-c"; 6071553Srgrimes av[2] = width; 6081553Srgrimes av[3] = length; 6091553Srgrimes av[4] = indent; 6101553Srgrimes n = 5; 6111553Srgrimes break; 6121553Srgrimes case 'r': /* print a fortran text file */ 6131553Srgrimes prog = RF; 6141553Srgrimes av[1] = width; 6151553Srgrimes av[2] = length; 6161553Srgrimes n = 3; 6171553Srgrimes break; 6181553Srgrimes case 't': /* print troff output */ 6191553Srgrimes case 'n': /* print ditroff output */ 6201553Srgrimes case 'd': /* print tex output */ 6211553Srgrimes (void) unlink(".railmag"); 6221553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 6231553Srgrimes syslog(LOG_ERR, "%s: cannot create .railmag", printer); 6241553Srgrimes (void) unlink(".railmag"); 6251553Srgrimes } else { 6261553Srgrimes for (n = 0; n < 4; n++) { 6271553Srgrimes if (fonts[n][0] != '/') 6281553Srgrimes (void) write(fo, _PATH_VFONT, 6291553Srgrimes sizeof(_PATH_VFONT) - 1); 6301553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 6311553Srgrimes (void) write(fo, "\n", 1); 6321553Srgrimes } 6331553Srgrimes (void) close(fo); 6341553Srgrimes } 6351553Srgrimes prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 6361553Srgrimes av[1] = pxwidth; 6371553Srgrimes av[2] = pxlength; 6381553Srgrimes n = 3; 6391553Srgrimes break; 6401553Srgrimes case 'c': /* print cifplot output */ 6411553Srgrimes prog = CF; 6421553Srgrimes av[1] = pxwidth; 6431553Srgrimes av[2] = pxlength; 6441553Srgrimes n = 3; 6451553Srgrimes break; 6461553Srgrimes case 'g': /* print plot(1G) output */ 6471553Srgrimes prog = GF; 6481553Srgrimes av[1] = pxwidth; 6491553Srgrimes av[2] = pxlength; 6501553Srgrimes n = 3; 6511553Srgrimes break; 6521553Srgrimes case 'v': /* print raster output */ 6531553Srgrimes prog = VF; 6541553Srgrimes av[1] = pxwidth; 6551553Srgrimes av[2] = pxlength; 6561553Srgrimes n = 3; 6571553Srgrimes break; 6581553Srgrimes default: 6591553Srgrimes (void) close(fi); 6601553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 6611553Srgrimes printer, format); 6621553Srgrimes return(ERROR); 6631553Srgrimes } 66415648Sjoerg if (prog == NULL) { 66515648Sjoerg (void) close(fi); 66615648Sjoerg syslog(LOG_ERR, 66715648Sjoerg "%s: no filter found in printcap for format character '%c'", 66815648Sjoerg printer, format); 66915648Sjoerg return(ERROR); 67015648Sjoerg } 67127635Simp if ((av[0] = strrchr(prog, '/')) != NULL) 6721553Srgrimes av[0]++; 6731553Srgrimes else 6741553Srgrimes av[0] = prog; 6751553Srgrimes av[n++] = "-n"; 6761553Srgrimes av[n++] = logname; 6771553Srgrimes av[n++] = "-h"; 6781553Srgrimes av[n++] = fromhost; 6791553Srgrimes av[n++] = AF; 6801553Srgrimes av[n] = 0; 6811553Srgrimes fo = pfd; 6821553Srgrimes if (ofilter > 0) { /* stop output filter */ 6831553Srgrimes write(ofd, "\031\1", 2); 6841553Srgrimes while ((pid = 6851553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 6861553Srgrimes ; 6871553Srgrimes if (status.w_stopval != WSTOPPED) { 6881553Srgrimes (void) close(fi); 68915648Sjoerg syslog(LOG_WARNING, 69015648Sjoerg "%s: output filter died (retcode=%d termsig=%d)", 69115648Sjoerg printer, status.w_retcode, status.w_termsig); 6921553Srgrimes return(REPRINT); 6931553Srgrimes } 6941553Srgrimes stopped++; 6951553Srgrimes } 6961553Srgrimesstart: 6971553Srgrimes if ((child = dofork(DORETURN)) == 0) { /* child */ 6981553Srgrimes dup2(fi, 0); 6991553Srgrimes dup2(fo, 1); 7001553Srgrimes n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 7011553Srgrimes if (n >= 0) 7021553Srgrimes dup2(n, 2); 7038094Sjkh closelog(); 70418569Sbde for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++) 7051553Srgrimes (void) close(n); 7061553Srgrimes execv(prog, av); 7071553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 7081553Srgrimes exit(2); 7091553Srgrimes } 7101553Srgrimes (void) close(fi); 7111553Srgrimes if (child < 0) 7121553Srgrimes status.w_retcode = 100; 7131553Srgrimes else 7141553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 7151553Srgrimes ; 7161553Srgrimes child = 0; 7171553Srgrimes prchild = 0; 7181553Srgrimes if (stopped) { /* restart output filter */ 7191553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 7201553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 7211553Srgrimes exit(1); 7221553Srgrimes } 7231553Srgrimes } 7241553Srgrimes tof = 0; 7251553Srgrimes 7261553Srgrimes /* Copy filter output to "lf" logfile */ 72727748Simp if ((fp = fopen(tempfile, "r"))) { 7281553Srgrimes while (fgets(buf, sizeof(buf), fp)) 7291553Srgrimes fputs(buf, stderr); 7301553Srgrimes fclose(fp); 7311553Srgrimes } 7321553Srgrimes 7331553Srgrimes if (!WIFEXITED(status)) { 73415648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 7351553Srgrimes printer, format, status.w_termsig); 7361553Srgrimes return(ERROR); 7371553Srgrimes } 7381553Srgrimes switch (status.w_retcode) { 7391553Srgrimes case 0: 7401553Srgrimes tof = 1; 7411553Srgrimes return(OK); 7421553Srgrimes case 1: 7431553Srgrimes return(REPRINT); 74415648Sjoerg case 2: 74515648Sjoerg return(ERROR); 7461553Srgrimes default: 74715648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 7481553Srgrimes printer, format, status.w_retcode); 74915648Sjoerg return(FILTERERR); 7501553Srgrimes } 7511553Srgrimes} 7521553Srgrimes 7531553Srgrimes/* 7541553Srgrimes * Send the daemon control file (cf) and any data files. 7551553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 7561553Srgrimes * 0 if all is well. 7571553Srgrimes */ 7581553Srgrimesstatic int 7591553Srgrimessendit(file) 7601553Srgrimes char *file; 7611553Srgrimes{ 7621553Srgrimes register int i, err = OK; 7631553Srgrimes char *cp, last[BUFSIZ]; 7641553Srgrimes 7651553Srgrimes /* 7661553Srgrimes * open control file 7671553Srgrimes */ 7681553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 7691553Srgrimes return(OK); 7701553Srgrimes /* 7711553Srgrimes * read the control file for work to do 7721553Srgrimes * 7731553Srgrimes * file format -- first character in the line is a command 7741553Srgrimes * rest of the line is the argument. 7751553Srgrimes * commands of interest are: 7761553Srgrimes * 7771553Srgrimes * a-z -- "file name" name of file to print 7781553Srgrimes * U -- "unlink" name of file to remove 7791553Srgrimes * (after we print it. (Pass 2 only)). 7801553Srgrimes */ 7811553Srgrimes 7821553Srgrimes /* 7831553Srgrimes * pass 1 7841553Srgrimes */ 7851553Srgrimes while (getline(cfp)) { 7861553Srgrimes again: 7871553Srgrimes if (line[0] == 'S') { 7881553Srgrimes cp = line+1; 7891553Srgrimes i = 0; 7901553Srgrimes while (*cp >= '0' && *cp <= '9') 7911553Srgrimes i = i * 10 + (*cp++ - '0'); 7921553Srgrimes fdev = i; 7931553Srgrimes cp++; 7941553Srgrimes i = 0; 7951553Srgrimes while (*cp >= '0' && *cp <= '9') 7961553Srgrimes i = i * 10 + (*cp++ - '0'); 7971553Srgrimes fino = i; 79824831Sbrian } else if (line[0] == 'H') { 79924831Sbrian strcpy(fromhost, line+1); 80024831Sbrian if (class[0] == '\0') 80127748Simp strncpy(class, line+1, sizeof(class) - 1); 80224831Sbrian } else if (line[0] == 'P') { 80327748Simp strncpy(logname, line+1, sizeof(logname) - 1); 80424831Sbrian if (RS) { /* restricted */ 80524831Sbrian if (getpwnam(logname) == NULL) { 80624831Sbrian sendmail(line+1, NOACCT); 80724831Sbrian err = ERROR; 80824831Sbrian break; 80924831Sbrian } 81024831Sbrian } 81124831Sbrian } else if (line[0] == 'I') { 81227748Simp strncpy(indent+2, line+1, sizeof(indent) - 3); 81324831Sbrian } else if (line[0] >= 'a' && line[0] <= 'z') { 8141553Srgrimes strcpy(last, line); 8151553Srgrimes while (i = getline(cfp)) 8161553Srgrimes if (strcmp(last, line)) 8171553Srgrimes break; 81824831Sbrian switch (sendfile('\3', last+1, *last)) { 8191553Srgrimes case OK: 8201553Srgrimes if (i) 8211553Srgrimes goto again; 8221553Srgrimes break; 8231553Srgrimes case REPRINT: 8241553Srgrimes (void) fclose(cfp); 8251553Srgrimes return(REPRINT); 8261553Srgrimes case ACCESS: 8271553Srgrimes sendmail(logname, ACCESS); 8281553Srgrimes case ERROR: 8291553Srgrimes err = ERROR; 8301553Srgrimes } 8311553Srgrimes break; 8321553Srgrimes } 8331553Srgrimes } 83424831Sbrian if (err == OK && sendfile('\2', file, '\0') > 0) { 8351553Srgrimes (void) fclose(cfp); 8361553Srgrimes return(REPRINT); 8371553Srgrimes } 8381553Srgrimes /* 8391553Srgrimes * pass 2 8401553Srgrimes */ 8411553Srgrimes fseek(cfp, 0L, 0); 8421553Srgrimes while (getline(cfp)) 84327748Simp if (line[0] == 'U' && !strchr(line+1, '/')) 8441553Srgrimes (void) unlink(line+1); 8451553Srgrimes /* 8461553Srgrimes * clean-up in case another control file exists 8471553Srgrimes */ 8481553Srgrimes (void) fclose(cfp); 8491553Srgrimes (void) unlink(file); 8501553Srgrimes return(err); 8511553Srgrimes} 8521553Srgrimes 8531553Srgrimes/* 8541553Srgrimes * Send a data file to the remote machine and spool it. 8551553Srgrimes * Return positive if we should try resending. 8561553Srgrimes */ 8571553Srgrimesstatic int 85824831Sbriansendfile(type, file, format) 8591553Srgrimes int type; 8601553Srgrimes char *file; 86124831Sbrian char format; 8621553Srgrimes{ 8631553Srgrimes register int f, i, amt; 8641553Srgrimes struct stat stb; 8651553Srgrimes char buf[BUFSIZ]; 86624831Sbrian int sizerr, resp, closedpr; 8671553Srgrimes 8681553Srgrimes if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 8691553Srgrimes return(ERROR); 8701553Srgrimes /* 8711553Srgrimes * Check to see if data file is a symbolic link. If so, it should 8721553Srgrimes * still point to the same file or someone is trying to print something 8731553Srgrimes * he shouldn't. 8741553Srgrimes */ 8751553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 8761553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 8771553Srgrimes return(ACCESS); 87824831Sbrian 87924831Sbrian sizerr = 0; 88024831Sbrian closedpr = 0; 88124831Sbrian if (type == '\3') { 88224831Sbrian if (IF) { 88324831Sbrian /* 88424831Sbrian * We're sending something with an ifilter, we have to 88524831Sbrian * run the ifilter and store the output as a 88624831Sbrian * temporary file (tfile)... the protocol requires us 88724831Sbrian * to send the file size 88824831Sbrian */ 88924831Sbrian char *av[15]; 89024831Sbrian int n; 89124831Sbrian int nfd; 89224831Sbrian int ifilter; 89324831Sbrian union wait status; 89424831Sbrian 89524831Sbrian strcpy(tfile,TFILENAME); 89624831Sbrian if ((tfd = mkstemp(tfile)) == -1) { 89724831Sbrian syslog(LOG_ERR, "mkstemp: %m"); 89824831Sbrian return(ERROR); 89924831Sbrian } 90027635Simp if ((av[0] = strrchr(IF, '/')) == NULL) 90124831Sbrian av[0] = IF; 90224831Sbrian else 90324831Sbrian av[0]++; 90424831Sbrian if (format == 'l') 90524831Sbrian av[n=1] = "-c"; 90624831Sbrian else 90724831Sbrian n = 0; 90824831Sbrian av[++n] = width; 90924831Sbrian av[++n] = length; 91024831Sbrian av[++n] = indent; 91124831Sbrian av[++n] = "-n"; 91224831Sbrian av[++n] = logname; 91324831Sbrian av[++n] = "-h"; 91424831Sbrian av[++n] = fromhost; 91524831Sbrian av[++n] = AF; 91624831Sbrian av[++n] = 0; 91724831Sbrian if ((ifilter = dofork(DORETURN)) == 0) { /* child */ 91824831Sbrian dup2(f, 0); 91924831Sbrian dup2(tfd, 1); 92024831Sbrian n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 92124831Sbrian if (n >= 0) 92224831Sbrian dup2(n, 2); 92324831Sbrian closelog(); 92424831Sbrian for (n = 3, nfd = getdtablesize(); n < nfd; n++) 92524831Sbrian (void) close(n); 92624831Sbrian execv(IF, av); 92724831Sbrian syslog(LOG_ERR, "cannot execv %s", IF); 92824831Sbrian exit(2); 92924831Sbrian } 93024831Sbrian (void) close(f); 93124831Sbrian if (ifilter < 0) 93224831Sbrian status.w_retcode = 100; 93324831Sbrian else 93424831Sbrian while ((pid = wait((int *)&status)) > 0 && 93524831Sbrian pid != ifilter) 93624831Sbrian ; 93724831Sbrian switch (status.w_retcode) { 93824831Sbrian case 0: 93924831Sbrian break; 94024831Sbrian case 1: 94124831Sbrian unlink(tfile); 94224831Sbrian return(REPRINT); 94324831Sbrian case 2: 94424831Sbrian unlink(tfile); 94524831Sbrian return(ERROR); 94624831Sbrian default: 94724831Sbrian syslog(LOG_WARNING, "%s: filter '%c' exited" 94824831Sbrian " (retcode=%d)", 94924831Sbrian printer, format, status.w_retcode); 95024831Sbrian unlink(tfile); 95124831Sbrian return(FILTERERR); 95224831Sbrian } 95324831Sbrian if (fstat(tfd, &stb) < 0) /* the size of tfile */ 95424831Sbrian return(ERROR); 95524831Sbrian f = tfd; 95624831Sbrian lseek(f,0,SEEK_SET); 95724831Sbrian } else if (ofilter) { 95824831Sbrian /* 95924831Sbrian * We're sending something with an ofilter, we have to 96024831Sbrian * store the output as a temporary file (tfile)... the 96124831Sbrian * protocol requires us to send the file size 96224831Sbrian */ 96324831Sbrian int i; 96424831Sbrian for (i = 0; i < stb.st_size; i += BUFSIZ) { 96524831Sbrian amt = BUFSIZ; 96624831Sbrian if (i + amt > stb.st_size) 96724831Sbrian amt = stb.st_size - i; 96824831Sbrian if (sizerr == 0 && read(f, buf, amt) != amt) { 96924831Sbrian sizerr = 1; 97024831Sbrian break; 97124831Sbrian } 97224831Sbrian if (write(ofd, buf, amt) != amt) { 97324831Sbrian (void) close(f); 97424831Sbrian return(REPRINT); 97524831Sbrian } 97624831Sbrian } 97724831Sbrian close(ofd); 97824831Sbrian close(f); 97924831Sbrian while ((i = wait(NULL)) > 0 && i != ofilter) 98024831Sbrian ; 98124831Sbrian ofilter = 0; 98224831Sbrian if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 98324831Sbrian openpr(); 98424831Sbrian return(ERROR); 98524831Sbrian } 98624831Sbrian f = tfd; 98724831Sbrian lseek(f,0,SEEK_SET); 98824831Sbrian closedpr = 1; 98924831Sbrian } 99024831Sbrian } 99124831Sbrian 9921553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 9931553Srgrimes amt = strlen(buf); 9941553Srgrimes for (i = 0; ; i++) { 9951553Srgrimes if (write(pfd, buf, amt) != amt || 9961553Srgrimes (resp = response()) < 0 || resp == '\1') { 9971553Srgrimes (void) close(f); 99824831Sbrian if (tfd != -1 && type == '\3') { 99924831Sbrian tfd = -1; 100024831Sbrian unlink(tfile); 100124831Sbrian if (closedpr) 100224831Sbrian openpr(); 100324831Sbrian } 10041553Srgrimes return(REPRINT); 10051553Srgrimes } else if (resp == '\0') 10061553Srgrimes break; 10071553Srgrimes if (i == 0) 10081553Srgrimes pstatus("no space on remote; waiting for queue to drain"); 10091553Srgrimes if (i == 10) 10101553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 10111553Srgrimes printer, RM); 10121553Srgrimes sleep(5 * 60); 10131553Srgrimes } 10141553Srgrimes if (i) 10151553Srgrimes pstatus("sending to %s", RM); 10161553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 10171553Srgrimes amt = BUFSIZ; 10181553Srgrimes if (i + amt > stb.st_size) 10191553Srgrimes amt = stb.st_size - i; 10201553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 10211553Srgrimes sizerr = 1; 10221553Srgrimes if (write(pfd, buf, amt) != amt) { 10231553Srgrimes (void) close(f); 102424831Sbrian if (tfd != -1 && type == '\3') { 102524831Sbrian tfd = -1; 102624831Sbrian unlink(tfile); 102724831Sbrian if (closedpr) 102824831Sbrian openpr(); 102924831Sbrian } 10301553Srgrimes return(REPRINT); 10311553Srgrimes } 10321553Srgrimes } 10331553Srgrimes 10341553Srgrimes (void) close(f); 103524831Sbrian if (tfd != -1 && type == '\3') { 103624831Sbrian tfd = -1; 103724831Sbrian unlink(tfile); 103824831Sbrian } 10391553Srgrimes if (sizerr) { 10401553Srgrimes syslog(LOG_INFO, "%s: %s: changed size", printer, file); 10411553Srgrimes /* tell recvjob to ignore this file */ 10421553Srgrimes (void) write(pfd, "\1", 1); 104324831Sbrian if (closedpr) 104424831Sbrian openpr(); 10451553Srgrimes return(ERROR); 10461553Srgrimes } 104724831Sbrian if (write(pfd, "", 1) != 1 || response()) { 104824831Sbrian if (closedpr) 104924831Sbrian openpr(); 10501553Srgrimes return(REPRINT); 105124831Sbrian } 105224831Sbrian if (closedpr) 105324831Sbrian openpr(); 10541553Srgrimes return(OK); 10551553Srgrimes} 10561553Srgrimes 10571553Srgrimes/* 10581553Srgrimes * Check to make sure there have been no errors and that both programs 10591553Srgrimes * are in sync with eachother. 10601553Srgrimes * Return non-zero if the connection was lost. 10611553Srgrimes */ 10621553Srgrimesstatic char 10631553Srgrimesresponse() 10641553Srgrimes{ 10651553Srgrimes char resp; 10661553Srgrimes 10671553Srgrimes if (read(pfd, &resp, 1) != 1) { 10681553Srgrimes syslog(LOG_INFO, "%s: lost connection", printer); 10691553Srgrimes return(-1); 10701553Srgrimes } 10711553Srgrimes return(resp); 10721553Srgrimes} 10731553Srgrimes 10741553Srgrimes/* 10751553Srgrimes * Banner printing stuff 10761553Srgrimes */ 10771553Srgrimesstatic void 10781553Srgrimesbanner(name1, name2) 10791553Srgrimes char *name1, *name2; 10801553Srgrimes{ 10811553Srgrimes time_t tvec; 10821553Srgrimes 10831553Srgrimes time(&tvec); 10841553Srgrimes if (!SF && !tof) 10851553Srgrimes (void) write(ofd, FF, strlen(FF)); 10861553Srgrimes if (SB) { /* short banner only */ 10871553Srgrimes if (class[0]) { 10881553Srgrimes (void) write(ofd, class, strlen(class)); 10891553Srgrimes (void) write(ofd, ":", 1); 10901553Srgrimes } 10911553Srgrimes (void) write(ofd, name1, strlen(name1)); 10921553Srgrimes (void) write(ofd, " Job: ", 7); 10931553Srgrimes (void) write(ofd, name2, strlen(name2)); 10941553Srgrimes (void) write(ofd, " Date: ", 8); 10951553Srgrimes (void) write(ofd, ctime(&tvec), 24); 10961553Srgrimes (void) write(ofd, "\n", 1); 10971553Srgrimes } else { /* normal banner */ 10981553Srgrimes (void) write(ofd, "\n\n\n", 3); 10991553Srgrimes scan_out(ofd, name1, '\0'); 11001553Srgrimes (void) write(ofd, "\n\n", 2); 11011553Srgrimes scan_out(ofd, name2, '\0'); 11021553Srgrimes if (class[0]) { 11031553Srgrimes (void) write(ofd,"\n\n\n",3); 11041553Srgrimes scan_out(ofd, class, '\0'); 11051553Srgrimes } 11061553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 11071553Srgrimes (void) write(ofd, name2, strlen(name2)); 11081553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 11091553Srgrimes (void) write(ofd, ctime(&tvec), 24); 11101553Srgrimes (void) write(ofd, "\n", 1); 11111553Srgrimes } 11121553Srgrimes if (!SF) 11131553Srgrimes (void) write(ofd, FF, strlen(FF)); 11141553Srgrimes tof = 1; 11151553Srgrimes} 11161553Srgrimes 11171553Srgrimesstatic char * 11181553Srgrimesscnline(key, p, c) 11191553Srgrimes register int key; 11201553Srgrimes register char *p; 11211553Srgrimes int c; 11221553Srgrimes{ 11231553Srgrimes register scnwidth; 11241553Srgrimes 11251553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 11261553Srgrimes key <<= 1; 11271553Srgrimes *p++ = key & 0200 ? c : BACKGND; 11281553Srgrimes } 11291553Srgrimes return (p); 11301553Srgrimes} 11311553Srgrimes 11321553Srgrimes#define TRC(q) (((q)-' ')&0177) 11331553Srgrimes 11341553Srgrimesstatic void 11351553Srgrimesscan_out(scfd, scsp, dlm) 11361553Srgrimes int scfd, dlm; 11371553Srgrimes char *scsp; 11381553Srgrimes{ 11391553Srgrimes register char *strp; 11401553Srgrimes register nchrs, j; 11411553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 11421553Srgrimes int d, scnhgt; 11431553Srgrimes 11441553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 11451553Srgrimes strp = &outbuf[0]; 11461553Srgrimes sp = scsp; 11471553Srgrimes for (nchrs = 0; ; ) { 11481553Srgrimes d = dropit(c = TRC(cc = *sp++)); 11491553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 11501553Srgrimes for (j = WIDTH; --j;) 11511553Srgrimes *strp++ = BACKGND; 11521553Srgrimes else 11531553Srgrimes strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 11541553Srgrimes if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 11551553Srgrimes break; 11561553Srgrimes *strp++ = BACKGND; 11571553Srgrimes *strp++ = BACKGND; 11581553Srgrimes } 11591553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 11601553Srgrimes ; 11611553Srgrimes strp++; 11628857Srgrimes *strp++ = '\n'; 11631553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 11641553Srgrimes } 11651553Srgrimes} 11661553Srgrimes 11671553Srgrimesstatic int 11681553Srgrimesdropit(c) 11691553Srgrimes int c; 11701553Srgrimes{ 11711553Srgrimes switch(c) { 11721553Srgrimes 11731553Srgrimes case TRC('_'): 11741553Srgrimes case TRC(';'): 11751553Srgrimes case TRC(','): 11761553Srgrimes case TRC('g'): 11771553Srgrimes case TRC('j'): 11781553Srgrimes case TRC('p'): 11791553Srgrimes case TRC('q'): 11801553Srgrimes case TRC('y'): 11811553Srgrimes return (DROP); 11821553Srgrimes 11831553Srgrimes default: 11841553Srgrimes return (0); 11851553Srgrimes } 11861553Srgrimes} 11871553Srgrimes 11881553Srgrimes/* 11891553Srgrimes * sendmail --- 11901553Srgrimes * tell people about job completion 11911553Srgrimes */ 11921553Srgrimesstatic void 11931553Srgrimessendmail(user, bombed) 11941553Srgrimes char *user; 11951553Srgrimes int bombed; 11961553Srgrimes{ 11971553Srgrimes register int i; 119818569Sbde int dtablesize; 11991553Srgrimes int p[2], s; 12001553Srgrimes register char *cp; 12011553Srgrimes struct stat stb; 12021553Srgrimes FILE *fp; 12031553Srgrimes 12041553Srgrimes pipe(p); 12051553Srgrimes if ((s = dofork(DORETURN)) == 0) { /* child */ 12061553Srgrimes dup2(p[0], 0); 12078094Sjkh closelog(); 120818569Sbde for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++) 12091553Srgrimes (void) close(i); 121027635Simp if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 12111553Srgrimes cp++; 12121553Srgrimes else 12131553Srgrimes cp = _PATH_SENDMAIL; 121427757Simp execl(_PATH_SENDMAIL, cp, "-t", 0); 12151553Srgrimes exit(0); 12161553Srgrimes } else if (s > 0) { /* parent */ 12171553Srgrimes dup2(p[1], 1); 12181553Srgrimes printf("To: %s@%s\n", user, fromhost); 121915648Sjoerg printf("Subject: %s printer job \"%s\"\n", printer, 122015648Sjoerg *jobname ? jobname : "<unknown>"); 122115648Sjoerg printf("Reply-To: root@%s\n\n", host); 12221553Srgrimes printf("Your printer job "); 12231553Srgrimes if (*jobname) 12241553Srgrimes printf("(%s) ", jobname); 12251553Srgrimes switch (bombed) { 12261553Srgrimes case OK: 12271553Srgrimes printf("\ncompleted successfully\n"); 122815648Sjoerg cp = "OK"; 12291553Srgrimes break; 12301553Srgrimes default: 12311553Srgrimes case FATALERR: 12321553Srgrimes printf("\ncould not be printed\n"); 123315648Sjoerg cp = "FATALERR"; 12341553Srgrimes break; 12351553Srgrimes case NOACCT: 12361553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 123715648Sjoerg cp = "NOACCT"; 12381553Srgrimes break; 12391553Srgrimes case FILTERERR: 12401553Srgrimes if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 12411553Srgrimes (fp = fopen(tempfile, "r")) == NULL) { 124215648Sjoerg printf("\nhad some errors and may not have printed\n"); 12431553Srgrimes break; 12441553Srgrimes } 124515648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 12461553Srgrimes while ((i = getc(fp)) != EOF) 12471553Srgrimes putchar(i); 12481553Srgrimes (void) fclose(fp); 124915648Sjoerg cp = "FILTERERR"; 12501553Srgrimes break; 12511553Srgrimes case ACCESS: 12521553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 125315648Sjoerg cp = "ACCESS"; 12541553Srgrimes } 12551553Srgrimes fflush(stdout); 12561553Srgrimes (void) close(1); 12571553Srgrimes } 12581553Srgrimes (void) close(p[0]); 12591553Srgrimes (void) close(p[1]); 126015648Sjoerg wait(NULL); 126115648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 126215648Sjoerg user, *jobname ? jobname : "<unknown>", printer, cp); 12631553Srgrimes} 12641553Srgrimes 12651553Srgrimes/* 12661553Srgrimes * dofork - fork with retries on failure 12671553Srgrimes */ 12681553Srgrimesstatic int 12691553Srgrimesdofork(action) 12701553Srgrimes int action; 12711553Srgrimes{ 12721553Srgrimes register int i, pid; 12731553Srgrimes 12741553Srgrimes for (i = 0; i < 20; i++) { 12751553Srgrimes if ((pid = fork()) < 0) { 12761553Srgrimes sleep((unsigned)(i*i)); 12771553Srgrimes continue; 12781553Srgrimes } 12791553Srgrimes /* 12801553Srgrimes * Child should run as daemon instead of root 12811553Srgrimes */ 128215648Sjoerg if (pid == 0) 12831553Srgrimes setuid(DU); 12841553Srgrimes return(pid); 12851553Srgrimes } 12861553Srgrimes syslog(LOG_ERR, "can't fork"); 12871553Srgrimes 12881553Srgrimes switch (action) { 12891553Srgrimes case DORETURN: 12901553Srgrimes return (-1); 12911553Srgrimes default: 12921553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 12931553Srgrimes /*FALL THRU*/ 12941553Srgrimes case DOABORT: 12951553Srgrimes exit(1); 12961553Srgrimes } 12971553Srgrimes /*NOTREACHED*/ 12981553Srgrimes} 12991553Srgrimes 13001553Srgrimes/* 13011553Srgrimes * Kill child processes to abort current job. 13021553Srgrimes */ 13031553Srgrimesstatic void 13041553Srgrimesabortpr(signo) 13051553Srgrimes int signo; 13061553Srgrimes{ 13071553Srgrimes (void) unlink(tempfile); 13081553Srgrimes kill(0, SIGINT); 13091553Srgrimes if (ofilter > 0) 13101553Srgrimes kill(ofilter, SIGCONT); 13111553Srgrimes while (wait(NULL) > 0) 13121553Srgrimes ; 131324831Sbrian if (ofilter > 0 && tfd != -1) 131424831Sbrian unlink(tfile); 13151553Srgrimes exit(0); 13161553Srgrimes} 13171553Srgrimes 13181553Srgrimesstatic void 13191553Srgrimesinit() 13201553Srgrimes{ 13211553Srgrimes int status; 13221553Srgrimes char *s; 13231553Srgrimes 13241553Srgrimes if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 13251553Srgrimes syslog(LOG_ERR, "can't open printer description file"); 13261553Srgrimes exit(1); 13271553Srgrimes } else if (status == -1) { 13281553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 13291553Srgrimes exit(1); 13301553Srgrimes } else if (status == -3) 13311553Srgrimes fatal("potential reference loop detected in printcap file"); 13321553Srgrimes 13331553Srgrimes if (cgetstr(bp, "lp", &LP) == -1) 13341553Srgrimes LP = _PATH_DEFDEVLP; 13351553Srgrimes if (cgetstr(bp, "rp", &RP) == -1) 13361553Srgrimes RP = DEFLP; 13371553Srgrimes if (cgetstr(bp, "lo", &LO) == -1) 13381553Srgrimes LO = DEFLOCK; 13391553Srgrimes if (cgetstr(bp, "st", &ST) == -1) 13401553Srgrimes ST = DEFSTAT; 13411553Srgrimes if (cgetstr(bp, "lf", &LF) == -1) 13421553Srgrimes LF = _PATH_CONSOLE; 13431553Srgrimes if (cgetstr(bp, "sd", &SD) == -1) 13441553Srgrimes SD = _PATH_DEFSPOOL; 13451553Srgrimes if (cgetnum(bp, "du", &DU) < 0) 13461553Srgrimes DU = DEFUID; 13471553Srgrimes if (cgetstr(bp,"ff", &FF) == -1) 13481553Srgrimes FF = DEFFF; 13491553Srgrimes if (cgetnum(bp, "pw", &PW) < 0) 13501553Srgrimes PW = DEFWIDTH; 135127748Simp sprintf(&width[2], "%ld", PW); 13521553Srgrimes if (cgetnum(bp, "pl", &PL) < 0) 13531553Srgrimes PL = DEFLENGTH; 135430407Sjoerg if (cgetnum(bp, "ct", &CT) < 0) 135530407Sjoerg CT = DEFTIMEOUT; 135627748Simp sprintf(&length[2], "%ld", PL); 13571553Srgrimes if (cgetnum(bp,"px", &PX) < 0) 13581553Srgrimes PX = 0; 135927748Simp sprintf(&pxwidth[2], "%ld", PX); 13601553Srgrimes if (cgetnum(bp, "py", &PY) < 0) 13611553Srgrimes PY = 0; 136227748Simp sprintf(&pxlength[2], "%ld", PY); 13631553Srgrimes cgetstr(bp, "rm", &RM); 136427748Simp if ((s = checkremote())) 13651553Srgrimes syslog(LOG_WARNING, s); 13661553Srgrimes 13671553Srgrimes cgetstr(bp, "af", &AF); 13681553Srgrimes cgetstr(bp, "of", &OF); 13691553Srgrimes cgetstr(bp, "if", &IF); 13701553Srgrimes cgetstr(bp, "rf", &RF); 13711553Srgrimes cgetstr(bp, "tf", &TF); 13721553Srgrimes cgetstr(bp, "nf", &NF); 13731553Srgrimes cgetstr(bp, "df", &DF); 13741553Srgrimes cgetstr(bp, "gf", &GF); 13751553Srgrimes cgetstr(bp, "vf", &VF); 13761553Srgrimes cgetstr(bp, "cf", &CF); 13771553Srgrimes cgetstr(bp, "tr", &TR); 137815032Ssef cgetstr(bp, "ms", &MS); 13791553Srgrimes 13801553Srgrimes RS = (cgetcap(bp, "rs", ':') != NULL); 13811553Srgrimes SF = (cgetcap(bp, "sf", ':') != NULL); 13821553Srgrimes SH = (cgetcap(bp, "sh", ':') != NULL); 13831553Srgrimes SB = (cgetcap(bp, "sb", ':') != NULL); 13841553Srgrimes HL = (cgetcap(bp, "hl", ':') != NULL); 13851553Srgrimes RW = (cgetcap(bp, "rw", ':') != NULL); 13861553Srgrimes 13871553Srgrimes cgetnum(bp, "br", &BR); 13881553Srgrimes 13891553Srgrimes tof = (cgetcap(bp, "fo", ':') == NULL); 13901553Srgrimes} 13911553Srgrimes 13921553Srgrimes/* 13931553Srgrimes * Acquire line printer or remote connection. 13941553Srgrimes */ 13951553Srgrimesstatic void 13961553Srgrimesopenpr() 13971553Srgrimes{ 139815648Sjoerg register int i; 139918569Sbde int dtablesize; 140015648Sjoerg char *cp; 14011553Srgrimes 140215648Sjoerg if (!remote && *LP) { 140327635Simp if (cp = strchr(LP, '@')) 140415648Sjoerg opennet(cp); 140515648Sjoerg else 140615648Sjoerg opentty(); 140715648Sjoerg } else if (remote) { 140815648Sjoerg openrem(); 14091553Srgrimes } else { 14101553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 14111553Srgrimes printer); 14121553Srgrimes exit(1); 14131553Srgrimes } 141415648Sjoerg 14151553Srgrimes /* 14161553Srgrimes * Start up an output filter, if needed. 14171553Srgrimes */ 141824831Sbrian if (OF && !IF && !ofilter) { 14191553Srgrimes int p[2]; 14201553Srgrimes 14211553Srgrimes pipe(p); 142224831Sbrian if (remote) { 142324831Sbrian strcpy(tfile,TFILENAME); 142424831Sbrian tfd = mkstemp(tfile); 142524831Sbrian } 14261553Srgrimes if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 14271553Srgrimes dup2(p[0], 0); /* pipe is std in */ 142824831Sbrian /* tfile/printer is stdout */ 142924831Sbrian dup2(remote ? tfd : pfd, 1); 14308094Sjkh closelog(); 143118569Sbde for (i = 3, dtablesize = getdtablesize(); 143218569Sbde i < dtablesize; i++) 14331553Srgrimes (void) close(i); 143427635Simp if ((cp = strrchr(OF, '/')) == NULL) 14351553Srgrimes cp = OF; 14361553Srgrimes else 14371553Srgrimes cp++; 14381553Srgrimes execl(OF, cp, width, length, 0); 14391553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, OF); 14401553Srgrimes exit(1); 14411553Srgrimes } 14421553Srgrimes (void) close(p[0]); /* close input side */ 14431553Srgrimes ofd = p[1]; /* use pipe for output */ 14441553Srgrimes } else { 14451553Srgrimes ofd = pfd; 14461553Srgrimes ofilter = 0; 14471553Srgrimes } 14481553Srgrimes} 14491553Srgrimes 145015648Sjoerg/* 145115648Sjoerg * Printer connected directly to the network 145215648Sjoerg * or to a terminal server on the net 145315648Sjoerg */ 145415648Sjoergstatic void 145515648Sjoergopennet(cp) 145615648Sjoerg char *cp; 145715648Sjoerg{ 145815648Sjoerg register int i; 145915648Sjoerg int resp, port; 146015648Sjoerg char save_ch; 146130407Sjoerg void (*savealrm)(int); 146215648Sjoerg 146315648Sjoerg save_ch = *cp; 146415648Sjoerg *cp = '\0'; 146515648Sjoerg port = atoi(LP); 146615648Sjoerg if (port <= 0) { 146715648Sjoerg syslog(LOG_ERR, "%s: bad port number: %s", printer, LP); 146815648Sjoerg exit(1); 146915648Sjoerg } 147015648Sjoerg *cp++ = save_ch; 147115648Sjoerg 147215648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 147315648Sjoerg resp = -1; 147430407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 147530407Sjoerg alarm(CT); 147615648Sjoerg pfd = getport(cp, port); 147730407Sjoerg (void)signal(SIGALRM, savealrm); 147815648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 147915648Sjoerg resp = 1; 148015648Sjoerg else if (pfd >= 0) { 148115648Sjoerg /* 148215648Sjoerg * need to delay a bit for rs232 lines 148315648Sjoerg * to stabilize in case printer is 148415648Sjoerg * connected via a terminal server 148515648Sjoerg */ 148615648Sjoerg delay(500); 148715648Sjoerg break; 148815648Sjoerg } 148915648Sjoerg if (i == 1) { 149015648Sjoerg if (resp < 0) 149115648Sjoerg pstatus("waiting for %s to come up", LP); 149215648Sjoerg else 149315648Sjoerg pstatus("waiting for access to printer on %s", LP); 149415648Sjoerg } 149515648Sjoerg sleep(i); 149615648Sjoerg } 149715648Sjoerg pstatus("sending to %s port %d", cp, port); 149815648Sjoerg} 149915648Sjoerg 150015648Sjoerg/* 150115648Sjoerg * Printer is connected to an RS232 port on this host 150215648Sjoerg */ 150315648Sjoergstatic void 150415648Sjoergopentty() 150515648Sjoerg{ 150615648Sjoerg register int i; 150715648Sjoerg int resp, port; 150815648Sjoerg 150915648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 151015648Sjoerg pfd = open(LP, RW ? O_RDWR : O_WRONLY); 151115648Sjoerg if (pfd >= 0) { 151215648Sjoerg delay(500); 151315648Sjoerg break; 151415648Sjoerg } 151515648Sjoerg if (errno == ENOENT) { 151615648Sjoerg syslog(LOG_ERR, "%s: %m", LP); 151715648Sjoerg exit(1); 151815648Sjoerg } 151915648Sjoerg if (i == 1) 152015648Sjoerg pstatus("waiting for %s to become ready (offline ?)", 152115648Sjoerg printer); 152215648Sjoerg sleep(i); 152315648Sjoerg } 152415648Sjoerg if (isatty(pfd)) 152515648Sjoerg setty(); 152615648Sjoerg pstatus("%s is ready and printing", printer); 152715648Sjoerg} 152815648Sjoerg 152915648Sjoerg/* 153015648Sjoerg * Printer is on a remote host 153115648Sjoerg */ 153215648Sjoergstatic void 153315648Sjoergopenrem() 153415648Sjoerg{ 153515648Sjoerg register int i, n; 153627748Simp int resp; 153730407Sjoerg void (*savealrm)(int); 153815648Sjoerg 153915648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 154015648Sjoerg resp = -1; 154130407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 154230407Sjoerg alarm(CT); 154315648Sjoerg pfd = getport(RM, 0); 154430407Sjoerg (void)signal(SIGALRM, savealrm); 154515648Sjoerg if (pfd >= 0) { 154627748Simp (void) snprintf(line, sizeof(line), "\2%s\n", RP); 154715648Sjoerg n = strlen(line); 154815648Sjoerg if (write(pfd, line, n) == n && 154915648Sjoerg (resp = response()) == '\0') 155015648Sjoerg break; 155115648Sjoerg (void) close(pfd); 155215648Sjoerg } 155315648Sjoerg if (i == 1) { 155415648Sjoerg if (resp < 0) 155515648Sjoerg pstatus("waiting for %s to come up", RM); 155615648Sjoerg else { 155715648Sjoerg pstatus("waiting for queue to be enabled on %s", 155815648Sjoerg RM); 155915648Sjoerg i = 256; 156015648Sjoerg } 156115648Sjoerg } 156215648Sjoerg sleep(i); 156315648Sjoerg } 156415648Sjoerg pstatus("sending to %s", RM); 156515648Sjoerg} 156615648Sjoerg 15671553Srgrimesstruct bauds { 15681553Srgrimes int baud; 15691553Srgrimes int speed; 15701553Srgrimes} bauds[] = { 15711553Srgrimes 50, B50, 15721553Srgrimes 75, B75, 15731553Srgrimes 110, B110, 15741553Srgrimes 134, B134, 15751553Srgrimes 150, B150, 15761553Srgrimes 200, B200, 15771553Srgrimes 300, B300, 15781553Srgrimes 600, B600, 15791553Srgrimes 1200, B1200, 15801553Srgrimes 1800, B1800, 15811553Srgrimes 2400, B2400, 15821553Srgrimes 4800, B4800, 15831553Srgrimes 9600, B9600, 15841553Srgrimes 19200, EXTA, 15851553Srgrimes 38400, EXTB, 15869821Swpaul 57600, B57600, 15879821Swpaul 115200, B115200, 15881553Srgrimes 0, 0 15891553Srgrimes}; 15901553Srgrimes 15911553Srgrimes/* 15921553Srgrimes * setup tty lines. 15931553Srgrimes */ 15941553Srgrimesstatic void 15951553Srgrimessetty() 15961553Srgrimes{ 159715032Ssef struct termios ttybuf; 159815032Ssef struct bauds *bp; 15991553Srgrimes 16001553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 16011553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 16021553Srgrimes exit(1); 16031553Srgrimes } 160415032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 160515032Ssef syslog(LOG_ERR, "%s: tcgetattr: %m", printer); 16061553Srgrimes exit(1); 16071553Srgrimes } 16081553Srgrimes if (BR > 0) { 16091553Srgrimes for (bp = bauds; bp->baud; bp++) 16101553Srgrimes if (BR == bp->baud) 16111553Srgrimes break; 16121553Srgrimes if (!bp->baud) { 16131553Srgrimes syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 16141553Srgrimes exit(1); 16151553Srgrimes } 161615032Ssef cfsetspeed(&ttybuf, bp->speed); 16171553Srgrimes } 161815032Ssef if (MS) { 161915032Ssef char *s = strdup(MS), *tmp; 162015032Ssef 162115032Ssef while (tmp = strsep (&s, ",")) { 162215032Ssef msearch(tmp, &ttybuf); 16231553Srgrimes } 16241553Srgrimes } 162515032Ssef if (MS || (BR > 0)) { 162615032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 162715032Ssef syslog(LOG_ERR, "%s: tcsetattr: %m", printer); 16281553Srgrimes } 16291553Srgrimes } 16301553Srgrimes} 16311553Srgrimes 163227757Simp#ifdef __STDC__ 16331553Srgrimes#include <stdarg.h> 16341553Srgrimes#else 16351553Srgrimes#include <varargs.h> 16361553Srgrimes#endif 16371553Srgrimes 163815648Sjoergstatic void 163927757Simp#ifdef __STDC__ 16401553Srgrimespstatus(const char *msg, ...) 16411553Srgrimes#else 16421553Srgrimespstatus(msg, va_alist) 16431553Srgrimes char *msg; 16441553Srgrimes va_dcl 16451553Srgrimes#endif 16461553Srgrimes{ 16471553Srgrimes register int fd; 16481553Srgrimes char buf[BUFSIZ]; 16491553Srgrimes va_list ap; 165027757Simp#ifdef __STDC__ 16511553Srgrimes va_start(ap, msg); 16521553Srgrimes#else 16531553Srgrimes va_start(ap); 16541553Srgrimes#endif 16551553Srgrimes 16561553Srgrimes umask(0); 16571553Srgrimes fd = open(ST, O_WRONLY|O_CREAT, 0664); 16581553Srgrimes if (fd < 0 || flock(fd, LOCK_EX) < 0) { 16591553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, ST); 16601553Srgrimes exit(1); 16611553Srgrimes } 16621553Srgrimes ftruncate(fd, 0); 166327757Simp (void)vsnprintf(buf, sizeof(buf) - 1, msg, ap); 16641553Srgrimes va_end(ap); 16651553Srgrimes strcat(buf, "\n"); 16661553Srgrimes (void) write(fd, buf, strlen(buf)); 16671553Srgrimes (void) close(fd); 16681553Srgrimes} 166930407Sjoerg 167030407Sjoergvoid 167130407Sjoergalarmhandler(signo) 167230407Sjoerg{ 167330407Sjoerg /* ignored */ 167430407Sjoerg} 1675