printjob.c revision 24831
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)); 1191553Srgrimesstatic void banner __P((char *, char *)); 1201553Srgrimesstatic int dofork __P((int)); 1211553Srgrimesstatic int dropit __P((int)); 1221553Srgrimesstatic void init __P((void)); 1231553Srgrimesstatic void openpr __P((void)); 12415648Sjoergstatic void opennet __P((char *)); 12515648Sjoergstatic void opentty __P((void)); 12615648Sjoergstatic void openrem __P((void)); 1271553Srgrimesstatic int print __P((int, char *)); 1281553Srgrimesstatic int printit __P((char *)); 1291553Srgrimesstatic void pstatus __P((const char *, ...)); 1301553Srgrimesstatic char response __P((void)); 1311553Srgrimesstatic void scan_out __P((int, char *, int)); 1321553Srgrimesstatic char *scnline __P((int, char *, int)); 13324831Sbrianstatic int sendfile __P((int, char *, char)); 1341553Srgrimesstatic int sendit __P((char *)); 1351553Srgrimesstatic void sendmail __P((char *, int)); 1361553Srgrimesstatic void setty __P((void)); 1371553Srgrimes 1381553Srgrimesvoid 1391553Srgrimesprintjob() 1401553Srgrimes{ 1411553Srgrimes struct stat stb; 1421553Srgrimes register struct queue *q, **qp; 1431553Srgrimes struct queue **queue; 1441553Srgrimes register int i, nitems; 14515648Sjoerg off_t pidoff; 14615648Sjoerg int errcnt, count = 0; 1471553Srgrimes 1481553Srgrimes init(); /* set up capabilities */ 1491553Srgrimes (void) write(1, "", 1); /* ack that daemon is started */ 1501553Srgrimes (void) close(2); /* set up log file */ 1511553Srgrimes if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 1521553Srgrimes syslog(LOG_ERR, "%s: %m", LF); 1531553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1541553Srgrimes } 1551553Srgrimes setgid(getegid()); 1561553Srgrimes pid = getpid(); /* for use with lprm */ 1571553Srgrimes setpgrp(0, pid); 1581553Srgrimes signal(SIGHUP, abortpr); 1591553Srgrimes signal(SIGINT, abortpr); 1601553Srgrimes signal(SIGQUIT, abortpr); 1611553Srgrimes signal(SIGTERM, abortpr); 1621553Srgrimes 1631553Srgrimes (void) mktemp(tempfile); 1641553Srgrimes 1651553Srgrimes /* 1661553Srgrimes * uses short form file names 1671553Srgrimes */ 1681553Srgrimes if (chdir(SD) < 0) { 1691553Srgrimes syslog(LOG_ERR, "%s: %m", SD); 1701553Srgrimes exit(1); 1711553Srgrimes } 1721553Srgrimes if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 1731553Srgrimes exit(0); /* printing disabled */ 1741553Srgrimes lfd = open(LO, O_WRONLY|O_CREAT, 0644); 1751553Srgrimes if (lfd < 0) { 1761553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1771553Srgrimes exit(1); 1781553Srgrimes } 1791553Srgrimes if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 1801553Srgrimes if (errno == EWOULDBLOCK) /* active deamon present */ 1811553Srgrimes exit(0); 1821553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1831553Srgrimes exit(1); 1841553Srgrimes } 1851553Srgrimes ftruncate(lfd, 0); 1861553Srgrimes /* 1871553Srgrimes * write process id for others to know 1881553Srgrimes */ 1891553Srgrimes sprintf(line, "%u\n", pid); 1901553Srgrimes pidoff = i = strlen(line); 1911553Srgrimes if (write(lfd, line, i) != i) { 1921553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1931553Srgrimes exit(1); 1941553Srgrimes } 1951553Srgrimes /* 1961553Srgrimes * search the spool directory for work and sort by queue order. 1971553Srgrimes */ 1981553Srgrimes if ((nitems = getq(&queue)) < 0) { 1991553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 2001553Srgrimes exit(1); 2011553Srgrimes } 2021553Srgrimes if (nitems == 0) /* no work to do */ 2031553Srgrimes exit(0); 2041553Srgrimes if (stb.st_mode & 01) { /* reset queue flag */ 2051553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2061553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2071553Srgrimes } 2081553Srgrimes openpr(); /* open printer or remote */ 2091553Srgrimesagain: 2101553Srgrimes /* 2111553Srgrimes * we found something to do now do it -- 2121553Srgrimes * write the name of the current control file into the lock file 2131553Srgrimes * so the spool queue program can tell what we're working on 2141553Srgrimes */ 2151553Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2161553Srgrimes q = *qp++; 2171553Srgrimes if (stat(q->q_name, &stb) < 0) 2181553Srgrimes continue; 21915648Sjoerg errcnt = 0; 2201553Srgrimes restart: 22115648Sjoerg (void) lseek(lfd, pidoff, 0); 2221553Srgrimes (void) sprintf(line, "%s\n", q->q_name); 2231553Srgrimes i = strlen(line); 2241553Srgrimes if (write(lfd, line, i) != i) 2251553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 2261553Srgrimes if (!remote) 2271553Srgrimes i = printit(q->q_name); 2281553Srgrimes else 2291553Srgrimes i = sendit(q->q_name); 2301553Srgrimes /* 2311553Srgrimes * Check to see if we are supposed to stop printing or 2321553Srgrimes * if we are to rebuild the queue. 2331553Srgrimes */ 2341553Srgrimes if (fstat(lfd, &stb) == 0) { 2351553Srgrimes /* stop printing before starting next job? */ 2361553Srgrimes if (stb.st_mode & 0100) 2371553Srgrimes goto done; 2381553Srgrimes /* rebuild queue (after lpc topq) */ 2391553Srgrimes if (stb.st_mode & 01) { 2401553Srgrimes for (free((char *) q); nitems--; free((char *) q)) 2411553Srgrimes q = *qp++; 2421553Srgrimes if (fchmod(lfd, stb.st_mode & 0776) < 0) 2431553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", 2441553Srgrimes printer, LO); 2451553Srgrimes break; 2461553Srgrimes } 2471553Srgrimes } 2481553Srgrimes if (i == OK) /* file ok and printed */ 2491553Srgrimes count++; 25015648Sjoerg else if (i == REPRINT && ++errcnt < 5) { 25115648Sjoerg /* try reprinting the job */ 2521553Srgrimes syslog(LOG_INFO, "restarting %s", printer); 2531553Srgrimes if (ofilter > 0) { 2541553Srgrimes kill(ofilter, SIGCONT); /* to be sure */ 2551553Srgrimes (void) close(ofd); 25615648Sjoerg while ((i = wait(NULL)) > 0 && i != ofilter) 2571553Srgrimes ; 2581553Srgrimes ofilter = 0; 2591553Srgrimes } 2601553Srgrimes (void) close(pfd); /* close printer */ 2611553Srgrimes if (ftruncate(lfd, pidoff) < 0) 2621553Srgrimes syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 2631553Srgrimes openpr(); /* try to reopen printer */ 2641553Srgrimes goto restart; 26515648Sjoerg } else { 26615648Sjoerg syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 26715648Sjoerg remote ? "sent to remote host" : "printed", q->q_name); 26815648Sjoerg if (i == REPRINT) { 26915648Sjoerg /* insure we don't attempt this job again */ 27015648Sjoerg (void) unlink(q->q_name); 27115648Sjoerg q->q_name[0] = 'd'; 27215648Sjoerg (void) unlink(q->q_name); 27315648Sjoerg if (logname[0]) 27415648Sjoerg sendmail(logname, FATALERR); 27515648Sjoerg } 2761553Srgrimes } 2771553Srgrimes } 2781553Srgrimes free((char *) queue); 2791553Srgrimes /* 2801553Srgrimes * search the spool directory for more work. 2811553Srgrimes */ 2821553Srgrimes if ((nitems = getq(&queue)) < 0) { 2831553Srgrimes syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 2841553Srgrimes exit(1); 2851553Srgrimes } 2861553Srgrimes if (nitems == 0) { /* no more work to do */ 2871553Srgrimes done: 2881553Srgrimes if (count > 0) { /* Files actually printed */ 2891553Srgrimes if (!SF && !tof) 2901553Srgrimes (void) write(ofd, FF, strlen(FF)); 2911553Srgrimes if (TR != NULL) /* output trailer */ 2921553Srgrimes (void) write(ofd, TR, strlen(TR)); 2931553Srgrimes } 29419202Simp (void) close(ofd); 29519202Simp (void) wait(NULL); 2961553Srgrimes (void) unlink(tempfile); 2971553Srgrimes exit(0); 2981553Srgrimes } 2991553Srgrimes goto again; 3001553Srgrimes} 3011553Srgrimes 3021553Srgrimeschar fonts[4][50]; /* fonts for troff */ 3031553Srgrimes 3041553Srgrimeschar ifonts[4][40] = { 3051553Srgrimes _PATH_VFONTR, 3061553Srgrimes _PATH_VFONTI, 3071553Srgrimes _PATH_VFONTB, 3081553Srgrimes _PATH_VFONTS, 3091553Srgrimes}; 3101553Srgrimes 3111553Srgrimes/* 3121553Srgrimes * The remaining part is the reading of the control file (cf) 3131553Srgrimes * and performing the various actions. 3141553Srgrimes */ 3151553Srgrimesstatic int 3161553Srgrimesprintit(file) 3171553Srgrimes char *file; 3181553Srgrimes{ 3191553Srgrimes register int i; 3201553Srgrimes char *cp; 3211553Srgrimes int bombed = OK; 3221553Srgrimes 3231553Srgrimes /* 3241553Srgrimes * open control file; ignore if no longer there. 3251553Srgrimes */ 3261553Srgrimes if ((cfp = fopen(file, "r")) == NULL) { 3271553Srgrimes syslog(LOG_INFO, "%s: %s: %m", printer, file); 3281553Srgrimes return(OK); 3291553Srgrimes } 3301553Srgrimes /* 3311553Srgrimes * Reset troff fonts. 3321553Srgrimes */ 3331553Srgrimes for (i = 0; i < 4; i++) 3341553Srgrimes strcpy(fonts[i], ifonts[i]); 3351553Srgrimes sprintf(&width[2], "%d", PW); 3361553Srgrimes strcpy(indent+2, "0"); 3371553Srgrimes 3381553Srgrimes /* 3391553Srgrimes * read the control file for work to do 3401553Srgrimes * 3411553Srgrimes * file format -- first character in the line is a command 3421553Srgrimes * rest of the line is the argument. 3431553Srgrimes * valid commands are: 3441553Srgrimes * 3451553Srgrimes * S -- "stat info" for symbolic link protection 3461553Srgrimes * J -- "job name" on banner page 3471553Srgrimes * C -- "class name" on banner page 3481553Srgrimes * L -- "literal" user's name to print on banner 3491553Srgrimes * T -- "title" for pr 3501553Srgrimes * H -- "host name" of machine where lpr was done 3511553Srgrimes * P -- "person" user's login name 3521553Srgrimes * I -- "indent" amount to indent output 35315648Sjoerg * R -- laser dpi "resolution" 3541553Srgrimes * f -- "file name" name of text file to print 3551553Srgrimes * l -- "file name" text file with control chars 3561553Srgrimes * p -- "file name" text file to print with pr(1) 3571553Srgrimes * t -- "file name" troff(1) file to print 3581553Srgrimes * n -- "file name" ditroff(1) file to print 3591553Srgrimes * d -- "file name" dvi file to print 3601553Srgrimes * g -- "file name" plot(1G) file to print 3611553Srgrimes * v -- "file name" plain raster file to print 3621553Srgrimes * c -- "file name" cifplot file to print 3631553Srgrimes * 1 -- "R font file" for troff 3641553Srgrimes * 2 -- "I font file" for troff 3651553Srgrimes * 3 -- "B font file" for troff 3661553Srgrimes * 4 -- "S font file" for troff 3671553Srgrimes * N -- "name" of file (used by lpq) 3681553Srgrimes * U -- "unlink" name of file to remove 3691553Srgrimes * (after we print it. (Pass 2 only)). 3701553Srgrimes * M -- "mail" to user when done printing 3711553Srgrimes * 3721553Srgrimes * getline reads a line and expands tabs to blanks 3731553Srgrimes */ 3741553Srgrimes 3751553Srgrimes /* pass 1 */ 3761553Srgrimes 3771553Srgrimes while (getline(cfp)) 3781553Srgrimes switch (line[0]) { 3791553Srgrimes case 'H': 3801553Srgrimes strcpy(fromhost, line+1); 3811553Srgrimes if (class[0] == '\0') 3821553Srgrimes strncpy(class, line+1, sizeof(class)-1); 3831553Srgrimes continue; 3841553Srgrimes 3851553Srgrimes case 'P': 3861553Srgrimes strncpy(logname, line+1, sizeof(logname)-1); 3871553Srgrimes if (RS) { /* restricted */ 3881553Srgrimes if (getpwnam(logname) == NULL) { 3891553Srgrimes bombed = NOACCT; 3901553Srgrimes sendmail(line+1, bombed); 3911553Srgrimes goto pass2; 3921553Srgrimes } 3931553Srgrimes } 3941553Srgrimes continue; 3951553Srgrimes 3961553Srgrimes case 'S': 3971553Srgrimes cp = line+1; 3981553Srgrimes i = 0; 3991553Srgrimes while (*cp >= '0' && *cp <= '9') 4001553Srgrimes i = i * 10 + (*cp++ - '0'); 4011553Srgrimes fdev = i; 4021553Srgrimes cp++; 4031553Srgrimes i = 0; 4041553Srgrimes while (*cp >= '0' && *cp <= '9') 4051553Srgrimes i = i * 10 + (*cp++ - '0'); 4061553Srgrimes fino = i; 4071553Srgrimes continue; 4081553Srgrimes 4091553Srgrimes case 'J': 4101553Srgrimes if (line[1] != '\0') 4111553Srgrimes strncpy(jobname, line+1, sizeof(jobname)-1); 4121553Srgrimes else 4131553Srgrimes strcpy(jobname, " "); 4141553Srgrimes continue; 4151553Srgrimes 4161553Srgrimes case 'C': 4171553Srgrimes if (line[1] != '\0') 4181553Srgrimes strncpy(class, line+1, sizeof(class)-1); 4191553Srgrimes else if (class[0] == '\0') 4201553Srgrimes gethostname(class, sizeof(class)); 4211553Srgrimes continue; 4221553Srgrimes 4231553Srgrimes case 'T': /* header title for pr */ 4241553Srgrimes strncpy(title, line+1, sizeof(title)-1); 4251553Srgrimes continue; 4261553Srgrimes 4271553Srgrimes case 'L': /* identification line */ 4281553Srgrimes if (!SH && !HL) 4291553Srgrimes banner(line+1, jobname); 4301553Srgrimes continue; 4311553Srgrimes 4321553Srgrimes case '1': /* troff fonts */ 4331553Srgrimes case '2': 4341553Srgrimes case '3': 4351553Srgrimes case '4': 4361553Srgrimes if (line[1] != '\0') 4371553Srgrimes strcpy(fonts[line[0]-'1'], line+1); 4381553Srgrimes continue; 4391553Srgrimes 4401553Srgrimes case 'W': /* page width */ 4411553Srgrimes strncpy(width+2, line+1, sizeof(width)-3); 4421553Srgrimes continue; 4431553Srgrimes 4441553Srgrimes case 'I': /* indent amount */ 4451553Srgrimes strncpy(indent+2, line+1, sizeof(indent)-3); 4461553Srgrimes continue; 4471553Srgrimes 4481553Srgrimes default: /* some file to print */ 4491553Srgrimes switch (i = print(line[0], line+1)) { 4501553Srgrimes case ERROR: 4511553Srgrimes if (bombed == OK) 4521553Srgrimes bombed = FATALERR; 4531553Srgrimes break; 4541553Srgrimes case REPRINT: 4551553Srgrimes (void) fclose(cfp); 4561553Srgrimes return(REPRINT); 4571553Srgrimes case FILTERERR: 4581553Srgrimes case ACCESS: 4591553Srgrimes bombed = i; 4601553Srgrimes sendmail(logname, bombed); 4611553Srgrimes } 4621553Srgrimes title[0] = '\0'; 4631553Srgrimes continue; 4641553Srgrimes 4651553Srgrimes case 'N': 4661553Srgrimes case 'U': 4671553Srgrimes case 'M': 46815648Sjoerg case 'R': 4691553Srgrimes continue; 4701553Srgrimes } 4711553Srgrimes 4721553Srgrimes /* pass 2 */ 4731553Srgrimes 4741553Srgrimespass2: 4751553Srgrimes fseek(cfp, 0L, 0); 4761553Srgrimes while (getline(cfp)) 4771553Srgrimes switch (line[0]) { 4781553Srgrimes case 'L': /* identification line */ 4791553Srgrimes if (!SH && HL) 4801553Srgrimes banner(line+1, jobname); 4811553Srgrimes continue; 4821553Srgrimes 4831553Srgrimes case 'M': 4841553Srgrimes if (bombed < NOACCT) /* already sent if >= NOACCT */ 4851553Srgrimes sendmail(line+1, bombed); 4861553Srgrimes continue; 4871553Srgrimes 4881553Srgrimes case 'U': 4891553Srgrimes (void) unlink(line+1); 4901553Srgrimes } 4911553Srgrimes /* 4921553Srgrimes * clean-up in case another control file exists 4931553Srgrimes */ 4941553Srgrimes (void) fclose(cfp); 4951553Srgrimes (void) unlink(file); 4961553Srgrimes return(bombed == OK ? OK : ERROR); 4971553Srgrimes} 4981553Srgrimes 4991553Srgrimes/* 5001553Srgrimes * Print a file. 5011553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 5021553Srgrimes * Return -1 if a non-recoverable error occured, 5031553Srgrimes * 2 if the filter detected some errors (but printed the job anyway), 5041553Srgrimes * 1 if we should try to reprint this job and 5051553Srgrimes * 0 if all is well. 5061553Srgrimes * Note: all filters take stdin as the file, stdout as the printer, 5071553Srgrimes * stderr as the log file, and must not ignore SIGINT. 5081553Srgrimes */ 5091553Srgrimesstatic int 5101553Srgrimesprint(format, file) 5111553Srgrimes int format; 5121553Srgrimes char *file; 5131553Srgrimes{ 5141553Srgrimes register int n; 5151553Srgrimes register char *prog; 51618569Sbde int dtablesize, fi, fo; 5171553Srgrimes FILE *fp; 5181553Srgrimes char *av[15], buf[BUFSIZ]; 5191553Srgrimes int pid, p[2], stopped = 0; 5201553Srgrimes union wait status; 5211553Srgrimes struct stat stb; 5221553Srgrimes 5231553Srgrimes if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 5241553Srgrimes return(ERROR); 5251553Srgrimes /* 5261553Srgrimes * Check to see if data file is a symbolic link. If so, it should 5271553Srgrimes * still point to the same file or someone is trying to print 5281553Srgrimes * something he shouldn't. 5291553Srgrimes */ 5301553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 5311553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 5321553Srgrimes return(ACCESS); 5331553Srgrimes if (!SF && !tof) { /* start on a fresh page */ 5341553Srgrimes (void) write(ofd, FF, strlen(FF)); 5351553Srgrimes tof = 1; 5361553Srgrimes } 5371553Srgrimes if (IF == NULL && (format == 'f' || format == 'l')) { 5381553Srgrimes tof = 0; 5391553Srgrimes while ((n = read(fi, buf, BUFSIZ)) > 0) 5401553Srgrimes if (write(ofd, buf, n) != n) { 5411553Srgrimes (void) close(fi); 5421553Srgrimes return(REPRINT); 5431553Srgrimes } 5441553Srgrimes (void) close(fi); 5451553Srgrimes return(OK); 5461553Srgrimes } 5471553Srgrimes switch (format) { 5481553Srgrimes case 'p': /* print file using 'pr' */ 5491553Srgrimes if (IF == NULL) { /* use output filter */ 5501553Srgrimes prog = _PATH_PR; 5511553Srgrimes av[0] = "pr"; 5521553Srgrimes av[1] = width; 5531553Srgrimes av[2] = length; 5541553Srgrimes av[3] = "-h"; 5551553Srgrimes av[4] = *title ? title : " "; 5565445Sjoerg av[5] = "-F"; 5575445Sjoerg av[6] = 0; 5581553Srgrimes fo = ofd; 5591553Srgrimes goto start; 5601553Srgrimes } 5611553Srgrimes pipe(p); 5621553Srgrimes if ((prchild = dofork(DORETURN)) == 0) { /* child */ 5631553Srgrimes dup2(fi, 0); /* file is stdin */ 5641553Srgrimes dup2(p[1], 1); /* pipe is stdout */ 5658094Sjkh closelog(); 56618569Sbde for (n = 3, dtablesize = getdtablesize(); 56718569Sbde n < dtablesize; n++) 5681553Srgrimes (void) close(n); 5691553Srgrimes execl(_PATH_PR, "pr", width, length, 5705445Sjoerg "-h", *title ? title : " ", "-F", 0); 5711553Srgrimes syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 5721553Srgrimes exit(2); 5731553Srgrimes } 5741553Srgrimes (void) close(p[1]); /* close output side */ 5751553Srgrimes (void) close(fi); 5761553Srgrimes if (prchild < 0) { 5771553Srgrimes prchild = 0; 5781553Srgrimes (void) close(p[0]); 5791553Srgrimes return(ERROR); 5801553Srgrimes } 5811553Srgrimes fi = p[0]; /* use pipe for input */ 5821553Srgrimes case 'f': /* print plain text file */ 5831553Srgrimes prog = IF; 5841553Srgrimes av[1] = width; 5851553Srgrimes av[2] = length; 5861553Srgrimes av[3] = indent; 5871553Srgrimes n = 4; 5881553Srgrimes break; 5891553Srgrimes case 'l': /* like 'f' but pass control characters */ 5901553Srgrimes prog = IF; 5911553Srgrimes av[1] = "-c"; 5921553Srgrimes av[2] = width; 5931553Srgrimes av[3] = length; 5941553Srgrimes av[4] = indent; 5951553Srgrimes n = 5; 5961553Srgrimes break; 5971553Srgrimes case 'r': /* print a fortran text file */ 5981553Srgrimes prog = RF; 5991553Srgrimes av[1] = width; 6001553Srgrimes av[2] = length; 6011553Srgrimes n = 3; 6021553Srgrimes break; 6031553Srgrimes case 't': /* print troff output */ 6041553Srgrimes case 'n': /* print ditroff output */ 6051553Srgrimes case 'd': /* print tex output */ 6061553Srgrimes (void) unlink(".railmag"); 6071553Srgrimes if ((fo = creat(".railmag", FILMOD)) < 0) { 6081553Srgrimes syslog(LOG_ERR, "%s: cannot create .railmag", printer); 6091553Srgrimes (void) unlink(".railmag"); 6101553Srgrimes } else { 6111553Srgrimes for (n = 0; n < 4; n++) { 6121553Srgrimes if (fonts[n][0] != '/') 6131553Srgrimes (void) write(fo, _PATH_VFONT, 6141553Srgrimes sizeof(_PATH_VFONT) - 1); 6151553Srgrimes (void) write(fo, fonts[n], strlen(fonts[n])); 6161553Srgrimes (void) write(fo, "\n", 1); 6171553Srgrimes } 6181553Srgrimes (void) close(fo); 6191553Srgrimes } 6201553Srgrimes prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 6211553Srgrimes av[1] = pxwidth; 6221553Srgrimes av[2] = pxlength; 6231553Srgrimes n = 3; 6241553Srgrimes break; 6251553Srgrimes case 'c': /* print cifplot output */ 6261553Srgrimes prog = CF; 6271553Srgrimes av[1] = pxwidth; 6281553Srgrimes av[2] = pxlength; 6291553Srgrimes n = 3; 6301553Srgrimes break; 6311553Srgrimes case 'g': /* print plot(1G) output */ 6321553Srgrimes prog = GF; 6331553Srgrimes av[1] = pxwidth; 6341553Srgrimes av[2] = pxlength; 6351553Srgrimes n = 3; 6361553Srgrimes break; 6371553Srgrimes case 'v': /* print raster output */ 6381553Srgrimes prog = VF; 6391553Srgrimes av[1] = pxwidth; 6401553Srgrimes av[2] = pxlength; 6411553Srgrimes n = 3; 6421553Srgrimes break; 6431553Srgrimes default: 6441553Srgrimes (void) close(fi); 6451553Srgrimes syslog(LOG_ERR, "%s: illegal format character '%c'", 6461553Srgrimes printer, format); 6471553Srgrimes return(ERROR); 6481553Srgrimes } 64915648Sjoerg if (prog == NULL) { 65015648Sjoerg (void) close(fi); 65115648Sjoerg syslog(LOG_ERR, 65215648Sjoerg "%s: no filter found in printcap for format character '%c'", 65315648Sjoerg printer, format); 65415648Sjoerg return(ERROR); 65515648Sjoerg } 6561553Srgrimes if ((av[0] = rindex(prog, '/')) != NULL) 6571553Srgrimes av[0]++; 6581553Srgrimes else 6591553Srgrimes av[0] = prog; 6601553Srgrimes av[n++] = "-n"; 6611553Srgrimes av[n++] = logname; 6621553Srgrimes av[n++] = "-h"; 6631553Srgrimes av[n++] = fromhost; 6641553Srgrimes av[n++] = AF; 6651553Srgrimes av[n] = 0; 6661553Srgrimes fo = pfd; 6671553Srgrimes if (ofilter > 0) { /* stop output filter */ 6681553Srgrimes write(ofd, "\031\1", 2); 6691553Srgrimes while ((pid = 6701553Srgrimes wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 6711553Srgrimes ; 6721553Srgrimes if (status.w_stopval != WSTOPPED) { 6731553Srgrimes (void) close(fi); 67415648Sjoerg syslog(LOG_WARNING, 67515648Sjoerg "%s: output filter died (retcode=%d termsig=%d)", 67615648Sjoerg printer, status.w_retcode, status.w_termsig); 6771553Srgrimes return(REPRINT); 6781553Srgrimes } 6791553Srgrimes stopped++; 6801553Srgrimes } 6811553Srgrimesstart: 6821553Srgrimes if ((child = dofork(DORETURN)) == 0) { /* child */ 6831553Srgrimes dup2(fi, 0); 6841553Srgrimes dup2(fo, 1); 6851553Srgrimes n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 6861553Srgrimes if (n >= 0) 6871553Srgrimes dup2(n, 2); 6888094Sjkh closelog(); 68918569Sbde for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++) 6901553Srgrimes (void) close(n); 6911553Srgrimes execv(prog, av); 6921553Srgrimes syslog(LOG_ERR, "cannot execv %s", prog); 6931553Srgrimes exit(2); 6941553Srgrimes } 6951553Srgrimes (void) close(fi); 6961553Srgrimes if (child < 0) 6971553Srgrimes status.w_retcode = 100; 6981553Srgrimes else 6991553Srgrimes while ((pid = wait((int *)&status)) > 0 && pid != child) 7001553Srgrimes ; 7011553Srgrimes child = 0; 7021553Srgrimes prchild = 0; 7031553Srgrimes if (stopped) { /* restart output filter */ 7041553Srgrimes if (kill(ofilter, SIGCONT) < 0) { 7051553Srgrimes syslog(LOG_ERR, "cannot restart output filter"); 7061553Srgrimes exit(1); 7071553Srgrimes } 7081553Srgrimes } 7091553Srgrimes tof = 0; 7101553Srgrimes 7111553Srgrimes /* Copy filter output to "lf" logfile */ 7121553Srgrimes if (fp = fopen(tempfile, "r")) { 7131553Srgrimes while (fgets(buf, sizeof(buf), fp)) 7141553Srgrimes fputs(buf, stderr); 7151553Srgrimes fclose(fp); 7161553Srgrimes } 7171553Srgrimes 7181553Srgrimes if (!WIFEXITED(status)) { 71915648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 7201553Srgrimes printer, format, status.w_termsig); 7211553Srgrimes return(ERROR); 7221553Srgrimes } 7231553Srgrimes switch (status.w_retcode) { 7241553Srgrimes case 0: 7251553Srgrimes tof = 1; 7261553Srgrimes return(OK); 7271553Srgrimes case 1: 7281553Srgrimes return(REPRINT); 72915648Sjoerg case 2: 73015648Sjoerg return(ERROR); 7311553Srgrimes default: 73215648Sjoerg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 7331553Srgrimes printer, format, status.w_retcode); 73415648Sjoerg return(FILTERERR); 7351553Srgrimes } 7361553Srgrimes} 7371553Srgrimes 7381553Srgrimes/* 7391553Srgrimes * Send the daemon control file (cf) and any data files. 7401553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 7411553Srgrimes * 0 if all is well. 7421553Srgrimes */ 7431553Srgrimesstatic int 7441553Srgrimessendit(file) 7451553Srgrimes char *file; 7461553Srgrimes{ 7471553Srgrimes register int i, err = OK; 7481553Srgrimes char *cp, last[BUFSIZ]; 7491553Srgrimes 7501553Srgrimes /* 7511553Srgrimes * open control file 7521553Srgrimes */ 7531553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 7541553Srgrimes return(OK); 7551553Srgrimes /* 7561553Srgrimes * read the control file for work to do 7571553Srgrimes * 7581553Srgrimes * file format -- first character in the line is a command 7591553Srgrimes * rest of the line is the argument. 7601553Srgrimes * commands of interest are: 7611553Srgrimes * 7621553Srgrimes * a-z -- "file name" name of file to print 7631553Srgrimes * U -- "unlink" name of file to remove 7641553Srgrimes * (after we print it. (Pass 2 only)). 7651553Srgrimes */ 7661553Srgrimes 7671553Srgrimes /* 7681553Srgrimes * pass 1 7691553Srgrimes */ 7701553Srgrimes while (getline(cfp)) { 7711553Srgrimes again: 7721553Srgrimes if (line[0] == 'S') { 7731553Srgrimes cp = line+1; 7741553Srgrimes i = 0; 7751553Srgrimes while (*cp >= '0' && *cp <= '9') 7761553Srgrimes i = i * 10 + (*cp++ - '0'); 7771553Srgrimes fdev = i; 7781553Srgrimes cp++; 7791553Srgrimes i = 0; 7801553Srgrimes while (*cp >= '0' && *cp <= '9') 7811553Srgrimes i = i * 10 + (*cp++ - '0'); 7821553Srgrimes fino = i; 78324831Sbrian } else if (line[0] == 'H') { 78424831Sbrian strcpy(fromhost, line+1); 78524831Sbrian if (class[0] == '\0') 78624831Sbrian strncpy(class, line+1, sizeof(class)-1); 78724831Sbrian } else if (line[0] == 'P') { 78824831Sbrian strncpy(logname, line+1, sizeof(logname)-1); 78924831Sbrian if (RS) { /* restricted */ 79024831Sbrian if (getpwnam(logname) == NULL) { 79124831Sbrian sendmail(line+1, NOACCT); 79224831Sbrian err = ERROR; 79324831Sbrian break; 79424831Sbrian } 79524831Sbrian } 79624831Sbrian } else if (line[0] == 'I') { 79724831Sbrian strncpy(indent+2, line+1, sizeof(indent)-3); 79824831Sbrian } else if (line[0] >= 'a' && line[0] <= 'z') { 7991553Srgrimes strcpy(last, line); 8001553Srgrimes while (i = getline(cfp)) 8011553Srgrimes if (strcmp(last, line)) 8021553Srgrimes break; 80324831Sbrian switch (sendfile('\3', last+1, *last)) { 8041553Srgrimes case OK: 8051553Srgrimes if (i) 8061553Srgrimes goto again; 8071553Srgrimes break; 8081553Srgrimes case REPRINT: 8091553Srgrimes (void) fclose(cfp); 8101553Srgrimes return(REPRINT); 8111553Srgrimes case ACCESS: 8121553Srgrimes sendmail(logname, ACCESS); 8131553Srgrimes case ERROR: 8141553Srgrimes err = ERROR; 8151553Srgrimes } 8161553Srgrimes break; 8171553Srgrimes } 8181553Srgrimes } 81924831Sbrian if (err == OK && sendfile('\2', file, '\0') > 0) { 8201553Srgrimes (void) fclose(cfp); 8211553Srgrimes return(REPRINT); 8221553Srgrimes } 8231553Srgrimes /* 8241553Srgrimes * pass 2 8251553Srgrimes */ 8261553Srgrimes fseek(cfp, 0L, 0); 8271553Srgrimes while (getline(cfp)) 8281553Srgrimes if (line[0] == 'U') 8291553Srgrimes (void) unlink(line+1); 8301553Srgrimes /* 8311553Srgrimes * clean-up in case another control file exists 8321553Srgrimes */ 8331553Srgrimes (void) fclose(cfp); 8341553Srgrimes (void) unlink(file); 8351553Srgrimes return(err); 8361553Srgrimes} 8371553Srgrimes 8381553Srgrimes/* 8391553Srgrimes * Send a data file to the remote machine and spool it. 8401553Srgrimes * Return positive if we should try resending. 8411553Srgrimes */ 8421553Srgrimesstatic int 84324831Sbriansendfile(type, file, format) 8441553Srgrimes int type; 8451553Srgrimes char *file; 84624831Sbrian char format; 8471553Srgrimes{ 8481553Srgrimes register int f, i, amt; 8491553Srgrimes struct stat stb; 8501553Srgrimes char buf[BUFSIZ]; 85124831Sbrian int sizerr, resp, closedpr; 8521553Srgrimes 8531553Srgrimes if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 8541553Srgrimes return(ERROR); 8551553Srgrimes /* 8561553Srgrimes * Check to see if data file is a symbolic link. If so, it should 8571553Srgrimes * still point to the same file or someone is trying to print something 8581553Srgrimes * he shouldn't. 8591553Srgrimes */ 8601553Srgrimes if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 8611553Srgrimes (stb.st_dev != fdev || stb.st_ino != fino)) 8621553Srgrimes return(ACCESS); 86324831Sbrian 86424831Sbrian sizerr = 0; 86524831Sbrian closedpr = 0; 86624831Sbrian if (type == '\3') { 86724831Sbrian if (IF) { 86824831Sbrian /* 86924831Sbrian * We're sending something with an ifilter, we have to 87024831Sbrian * run the ifilter and store the output as a 87124831Sbrian * temporary file (tfile)... the protocol requires us 87224831Sbrian * to send the file size 87324831Sbrian */ 87424831Sbrian char *av[15]; 87524831Sbrian int n; 87624831Sbrian int nfd; 87724831Sbrian int ifilter; 87824831Sbrian union wait status; 87924831Sbrian 88024831Sbrian strcpy(tfile,TFILENAME); 88124831Sbrian if ((tfd = mkstemp(tfile)) == -1) { 88224831Sbrian syslog(LOG_ERR, "mkstemp: %m"); 88324831Sbrian return(ERROR); 88424831Sbrian } 88524831Sbrian if ((av[0] = rindex(IF, '/')) == NULL) 88624831Sbrian av[0] = IF; 88724831Sbrian else 88824831Sbrian av[0]++; 88924831Sbrian if (format == 'l') 89024831Sbrian av[n=1] = "-c"; 89124831Sbrian else 89224831Sbrian n = 0; 89324831Sbrian av[++n] = width; 89424831Sbrian av[++n] = length; 89524831Sbrian av[++n] = indent; 89624831Sbrian av[++n] = "-n"; 89724831Sbrian av[++n] = logname; 89824831Sbrian av[++n] = "-h"; 89924831Sbrian av[++n] = fromhost; 90024831Sbrian av[++n] = AF; 90124831Sbrian av[++n] = 0; 90224831Sbrian if ((ifilter = dofork(DORETURN)) == 0) { /* child */ 90324831Sbrian dup2(f, 0); 90424831Sbrian dup2(tfd, 1); 90524831Sbrian n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 90624831Sbrian if (n >= 0) 90724831Sbrian dup2(n, 2); 90824831Sbrian closelog(); 90924831Sbrian for (n = 3, nfd = getdtablesize(); n < nfd; n++) 91024831Sbrian (void) close(n); 91124831Sbrian execv(IF, av); 91224831Sbrian syslog(LOG_ERR, "cannot execv %s", IF); 91324831Sbrian exit(2); 91424831Sbrian } 91524831Sbrian (void) close(f); 91624831Sbrian if (ifilter < 0) 91724831Sbrian status.w_retcode = 100; 91824831Sbrian else 91924831Sbrian while ((pid = wait((int *)&status)) > 0 && 92024831Sbrian pid != ifilter) 92124831Sbrian ; 92224831Sbrian switch (status.w_retcode) { 92324831Sbrian case 0: 92424831Sbrian break; 92524831Sbrian case 1: 92624831Sbrian unlink(tfile); 92724831Sbrian return(REPRINT); 92824831Sbrian case 2: 92924831Sbrian unlink(tfile); 93024831Sbrian return(ERROR); 93124831Sbrian default: 93224831Sbrian syslog(LOG_WARNING, "%s: filter '%c' exited" 93324831Sbrian " (retcode=%d)", 93424831Sbrian printer, format, status.w_retcode); 93524831Sbrian unlink(tfile); 93624831Sbrian return(FILTERERR); 93724831Sbrian } 93824831Sbrian if (fstat(tfd, &stb) < 0) /* the size of tfile */ 93924831Sbrian return(ERROR); 94024831Sbrian f = tfd; 94124831Sbrian lseek(f,0,SEEK_SET); 94224831Sbrian } else if (ofilter) { 94324831Sbrian /* 94424831Sbrian * We're sending something with an ofilter, we have to 94524831Sbrian * store the output as a temporary file (tfile)... the 94624831Sbrian * protocol requires us to send the file size 94724831Sbrian */ 94824831Sbrian int i; 94924831Sbrian for (i = 0; i < stb.st_size; i += BUFSIZ) { 95024831Sbrian amt = BUFSIZ; 95124831Sbrian if (i + amt > stb.st_size) 95224831Sbrian amt = stb.st_size - i; 95324831Sbrian if (sizerr == 0 && read(f, buf, amt) != amt) { 95424831Sbrian sizerr = 1; 95524831Sbrian break; 95624831Sbrian } 95724831Sbrian if (write(ofd, buf, amt) != amt) { 95824831Sbrian (void) close(f); 95924831Sbrian return(REPRINT); 96024831Sbrian } 96124831Sbrian } 96224831Sbrian close(ofd); 96324831Sbrian close(f); 96424831Sbrian while ((i = wait(NULL)) > 0 && i != ofilter) 96524831Sbrian ; 96624831Sbrian ofilter = 0; 96724831Sbrian if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 96824831Sbrian openpr(); 96924831Sbrian return(ERROR); 97024831Sbrian } 97124831Sbrian f = tfd; 97224831Sbrian lseek(f,0,SEEK_SET); 97324831Sbrian closedpr = 1; 97424831Sbrian } 97524831Sbrian } 97624831Sbrian 9771553Srgrimes (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 9781553Srgrimes amt = strlen(buf); 9791553Srgrimes for (i = 0; ; i++) { 9801553Srgrimes if (write(pfd, buf, amt) != amt || 9811553Srgrimes (resp = response()) < 0 || resp == '\1') { 9821553Srgrimes (void) close(f); 98324831Sbrian if (tfd != -1 && type == '\3') { 98424831Sbrian tfd = -1; 98524831Sbrian unlink(tfile); 98624831Sbrian if (closedpr) 98724831Sbrian openpr(); 98824831Sbrian } 9891553Srgrimes return(REPRINT); 9901553Srgrimes } else if (resp == '\0') 9911553Srgrimes break; 9921553Srgrimes if (i == 0) 9931553Srgrimes pstatus("no space on remote; waiting for queue to drain"); 9941553Srgrimes if (i == 10) 9951553Srgrimes syslog(LOG_ALERT, "%s: can't send to %s; queue full", 9961553Srgrimes printer, RM); 9971553Srgrimes sleep(5 * 60); 9981553Srgrimes } 9991553Srgrimes if (i) 10001553Srgrimes pstatus("sending to %s", RM); 10011553Srgrimes for (i = 0; i < stb.st_size; i += BUFSIZ) { 10021553Srgrimes amt = BUFSIZ; 10031553Srgrimes if (i + amt > stb.st_size) 10041553Srgrimes amt = stb.st_size - i; 10051553Srgrimes if (sizerr == 0 && read(f, buf, amt) != amt) 10061553Srgrimes sizerr = 1; 10071553Srgrimes if (write(pfd, buf, amt) != amt) { 10081553Srgrimes (void) close(f); 100924831Sbrian if (tfd != -1 && type == '\3') { 101024831Sbrian tfd = -1; 101124831Sbrian unlink(tfile); 101224831Sbrian if (closedpr) 101324831Sbrian openpr(); 101424831Sbrian } 10151553Srgrimes return(REPRINT); 10161553Srgrimes } 10171553Srgrimes } 10181553Srgrimes 10191553Srgrimes (void) close(f); 102024831Sbrian if (tfd != -1 && type == '\3') { 102124831Sbrian tfd = -1; 102224831Sbrian unlink(tfile); 102324831Sbrian } 10241553Srgrimes if (sizerr) { 10251553Srgrimes syslog(LOG_INFO, "%s: %s: changed size", printer, file); 10261553Srgrimes /* tell recvjob to ignore this file */ 10271553Srgrimes (void) write(pfd, "\1", 1); 102824831Sbrian if (closedpr) 102924831Sbrian openpr(); 10301553Srgrimes return(ERROR); 10311553Srgrimes } 103224831Sbrian if (write(pfd, "", 1) != 1 || response()) { 103324831Sbrian if (closedpr) 103424831Sbrian openpr(); 10351553Srgrimes return(REPRINT); 103624831Sbrian } 103724831Sbrian if (closedpr) 103824831Sbrian openpr(); 10391553Srgrimes return(OK); 10401553Srgrimes} 10411553Srgrimes 10421553Srgrimes/* 10431553Srgrimes * Check to make sure there have been no errors and that both programs 10441553Srgrimes * are in sync with eachother. 10451553Srgrimes * Return non-zero if the connection was lost. 10461553Srgrimes */ 10471553Srgrimesstatic char 10481553Srgrimesresponse() 10491553Srgrimes{ 10501553Srgrimes char resp; 10511553Srgrimes 10521553Srgrimes if (read(pfd, &resp, 1) != 1) { 10531553Srgrimes syslog(LOG_INFO, "%s: lost connection", printer); 10541553Srgrimes return(-1); 10551553Srgrimes } 10561553Srgrimes return(resp); 10571553Srgrimes} 10581553Srgrimes 10591553Srgrimes/* 10601553Srgrimes * Banner printing stuff 10611553Srgrimes */ 10621553Srgrimesstatic void 10631553Srgrimesbanner(name1, name2) 10641553Srgrimes char *name1, *name2; 10651553Srgrimes{ 10661553Srgrimes time_t tvec; 10671553Srgrimes 10681553Srgrimes time(&tvec); 10691553Srgrimes if (!SF && !tof) 10701553Srgrimes (void) write(ofd, FF, strlen(FF)); 10711553Srgrimes if (SB) { /* short banner only */ 10721553Srgrimes if (class[0]) { 10731553Srgrimes (void) write(ofd, class, strlen(class)); 10741553Srgrimes (void) write(ofd, ":", 1); 10751553Srgrimes } 10761553Srgrimes (void) write(ofd, name1, strlen(name1)); 10771553Srgrimes (void) write(ofd, " Job: ", 7); 10781553Srgrimes (void) write(ofd, name2, strlen(name2)); 10791553Srgrimes (void) write(ofd, " Date: ", 8); 10801553Srgrimes (void) write(ofd, ctime(&tvec), 24); 10811553Srgrimes (void) write(ofd, "\n", 1); 10821553Srgrimes } else { /* normal banner */ 10831553Srgrimes (void) write(ofd, "\n\n\n", 3); 10841553Srgrimes scan_out(ofd, name1, '\0'); 10851553Srgrimes (void) write(ofd, "\n\n", 2); 10861553Srgrimes scan_out(ofd, name2, '\0'); 10871553Srgrimes if (class[0]) { 10881553Srgrimes (void) write(ofd,"\n\n\n",3); 10891553Srgrimes scan_out(ofd, class, '\0'); 10901553Srgrimes } 10911553Srgrimes (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 10921553Srgrimes (void) write(ofd, name2, strlen(name2)); 10931553Srgrimes (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 10941553Srgrimes (void) write(ofd, ctime(&tvec), 24); 10951553Srgrimes (void) write(ofd, "\n", 1); 10961553Srgrimes } 10971553Srgrimes if (!SF) 10981553Srgrimes (void) write(ofd, FF, strlen(FF)); 10991553Srgrimes tof = 1; 11001553Srgrimes} 11011553Srgrimes 11021553Srgrimesstatic char * 11031553Srgrimesscnline(key, p, c) 11041553Srgrimes register int key; 11051553Srgrimes register char *p; 11061553Srgrimes int c; 11071553Srgrimes{ 11081553Srgrimes register scnwidth; 11091553Srgrimes 11101553Srgrimes for (scnwidth = WIDTH; --scnwidth;) { 11111553Srgrimes key <<= 1; 11121553Srgrimes *p++ = key & 0200 ? c : BACKGND; 11131553Srgrimes } 11141553Srgrimes return (p); 11151553Srgrimes} 11161553Srgrimes 11171553Srgrimes#define TRC(q) (((q)-' ')&0177) 11181553Srgrimes 11191553Srgrimesstatic void 11201553Srgrimesscan_out(scfd, scsp, dlm) 11211553Srgrimes int scfd, dlm; 11221553Srgrimes char *scsp; 11231553Srgrimes{ 11241553Srgrimes register char *strp; 11251553Srgrimes register nchrs, j; 11261553Srgrimes char outbuf[LINELEN+1], *sp, c, cc; 11271553Srgrimes int d, scnhgt; 11281553Srgrimes 11291553Srgrimes for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 11301553Srgrimes strp = &outbuf[0]; 11311553Srgrimes sp = scsp; 11321553Srgrimes for (nchrs = 0; ; ) { 11331553Srgrimes d = dropit(c = TRC(cc = *sp++)); 11341553Srgrimes if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 11351553Srgrimes for (j = WIDTH; --j;) 11361553Srgrimes *strp++ = BACKGND; 11371553Srgrimes else 11381553Srgrimes strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 11391553Srgrimes if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 11401553Srgrimes break; 11411553Srgrimes *strp++ = BACKGND; 11421553Srgrimes *strp++ = BACKGND; 11431553Srgrimes } 11441553Srgrimes while (*--strp == BACKGND && strp >= outbuf) 11451553Srgrimes ; 11461553Srgrimes strp++; 11478857Srgrimes *strp++ = '\n'; 11481553Srgrimes (void) write(scfd, outbuf, strp-outbuf); 11491553Srgrimes } 11501553Srgrimes} 11511553Srgrimes 11521553Srgrimesstatic int 11531553Srgrimesdropit(c) 11541553Srgrimes int c; 11551553Srgrimes{ 11561553Srgrimes switch(c) { 11571553Srgrimes 11581553Srgrimes case TRC('_'): 11591553Srgrimes case TRC(';'): 11601553Srgrimes case TRC(','): 11611553Srgrimes case TRC('g'): 11621553Srgrimes case TRC('j'): 11631553Srgrimes case TRC('p'): 11641553Srgrimes case TRC('q'): 11651553Srgrimes case TRC('y'): 11661553Srgrimes return (DROP); 11671553Srgrimes 11681553Srgrimes default: 11691553Srgrimes return (0); 11701553Srgrimes } 11711553Srgrimes} 11721553Srgrimes 11731553Srgrimes/* 11741553Srgrimes * sendmail --- 11751553Srgrimes * tell people about job completion 11761553Srgrimes */ 11771553Srgrimesstatic void 11781553Srgrimessendmail(user, bombed) 11791553Srgrimes char *user; 11801553Srgrimes int bombed; 11811553Srgrimes{ 11821553Srgrimes register int i; 118318569Sbde int dtablesize; 11841553Srgrimes int p[2], s; 11851553Srgrimes register char *cp; 11861553Srgrimes char buf[100]; 11871553Srgrimes struct stat stb; 11881553Srgrimes FILE *fp; 11891553Srgrimes 11901553Srgrimes pipe(p); 11911553Srgrimes if ((s = dofork(DORETURN)) == 0) { /* child */ 11921553Srgrimes dup2(p[0], 0); 11938094Sjkh closelog(); 119418569Sbde for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++) 11951553Srgrimes (void) close(i); 11961553Srgrimes if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 11971553Srgrimes cp++; 11981553Srgrimes else 11991553Srgrimes cp = _PATH_SENDMAIL; 12001553Srgrimes sprintf(buf, "%s@%s", user, fromhost); 12011553Srgrimes execl(_PATH_SENDMAIL, cp, buf, 0); 12021553Srgrimes exit(0); 12031553Srgrimes } else if (s > 0) { /* parent */ 12041553Srgrimes dup2(p[1], 1); 12051553Srgrimes printf("To: %s@%s\n", user, fromhost); 120615648Sjoerg printf("Subject: %s printer job \"%s\"\n", printer, 120715648Sjoerg *jobname ? jobname : "<unknown>"); 120815648Sjoerg printf("Reply-To: root@%s\n\n", host); 12091553Srgrimes printf("Your printer job "); 12101553Srgrimes if (*jobname) 12111553Srgrimes printf("(%s) ", jobname); 12121553Srgrimes switch (bombed) { 12131553Srgrimes case OK: 12141553Srgrimes printf("\ncompleted successfully\n"); 121515648Sjoerg cp = "OK"; 12161553Srgrimes break; 12171553Srgrimes default: 12181553Srgrimes case FATALERR: 12191553Srgrimes printf("\ncould not be printed\n"); 122015648Sjoerg cp = "FATALERR"; 12211553Srgrimes break; 12221553Srgrimes case NOACCT: 12231553Srgrimes printf("\ncould not be printed without an account on %s\n", host); 122415648Sjoerg cp = "NOACCT"; 12251553Srgrimes break; 12261553Srgrimes case FILTERERR: 12271553Srgrimes if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 12281553Srgrimes (fp = fopen(tempfile, "r")) == NULL) { 122915648Sjoerg printf("\nhad some errors and may not have printed\n"); 12301553Srgrimes break; 12311553Srgrimes } 123215648Sjoerg printf("\nhad the following errors and may not have printed:\n"); 12331553Srgrimes while ((i = getc(fp)) != EOF) 12341553Srgrimes putchar(i); 12351553Srgrimes (void) fclose(fp); 123615648Sjoerg cp = "FILTERERR"; 12371553Srgrimes break; 12381553Srgrimes case ACCESS: 12391553Srgrimes printf("\nwas not printed because it was not linked to the original file\n"); 124015648Sjoerg cp = "ACCESS"; 12411553Srgrimes } 12421553Srgrimes fflush(stdout); 12431553Srgrimes (void) close(1); 12441553Srgrimes } 12451553Srgrimes (void) close(p[0]); 12461553Srgrimes (void) close(p[1]); 124715648Sjoerg wait(NULL); 124815648Sjoerg syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 124915648Sjoerg user, *jobname ? jobname : "<unknown>", printer, cp); 12501553Srgrimes} 12511553Srgrimes 12521553Srgrimes/* 12531553Srgrimes * dofork - fork with retries on failure 12541553Srgrimes */ 12551553Srgrimesstatic int 12561553Srgrimesdofork(action) 12571553Srgrimes int action; 12581553Srgrimes{ 12591553Srgrimes register int i, pid; 12601553Srgrimes 12611553Srgrimes for (i = 0; i < 20; i++) { 12621553Srgrimes if ((pid = fork()) < 0) { 12631553Srgrimes sleep((unsigned)(i*i)); 12641553Srgrimes continue; 12651553Srgrimes } 12661553Srgrimes /* 12671553Srgrimes * Child should run as daemon instead of root 12681553Srgrimes */ 126915648Sjoerg if (pid == 0) 12701553Srgrimes setuid(DU); 12711553Srgrimes return(pid); 12721553Srgrimes } 12731553Srgrimes syslog(LOG_ERR, "can't fork"); 12741553Srgrimes 12751553Srgrimes switch (action) { 12761553Srgrimes case DORETURN: 12771553Srgrimes return (-1); 12781553Srgrimes default: 12791553Srgrimes syslog(LOG_ERR, "bad action (%d) to dofork", action); 12801553Srgrimes /*FALL THRU*/ 12811553Srgrimes case DOABORT: 12821553Srgrimes exit(1); 12831553Srgrimes } 12841553Srgrimes /*NOTREACHED*/ 12851553Srgrimes} 12861553Srgrimes 12871553Srgrimes/* 12881553Srgrimes * Kill child processes to abort current job. 12891553Srgrimes */ 12901553Srgrimesstatic void 12911553Srgrimesabortpr(signo) 12921553Srgrimes int signo; 12931553Srgrimes{ 12941553Srgrimes (void) unlink(tempfile); 12951553Srgrimes kill(0, SIGINT); 12961553Srgrimes if (ofilter > 0) 12971553Srgrimes kill(ofilter, SIGCONT); 12981553Srgrimes while (wait(NULL) > 0) 12991553Srgrimes ; 130024831Sbrian if (ofilter > 0 && tfd != -1) 130124831Sbrian unlink(tfile); 13021553Srgrimes exit(0); 13031553Srgrimes} 13041553Srgrimes 13051553Srgrimesstatic void 13061553Srgrimesinit() 13071553Srgrimes{ 13081553Srgrimes int status; 13091553Srgrimes char *s; 13101553Srgrimes 13111553Srgrimes if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 13121553Srgrimes syslog(LOG_ERR, "can't open printer description file"); 13131553Srgrimes exit(1); 13141553Srgrimes } else if (status == -1) { 13151553Srgrimes syslog(LOG_ERR, "unknown printer: %s", printer); 13161553Srgrimes exit(1); 13171553Srgrimes } else if (status == -3) 13181553Srgrimes fatal("potential reference loop detected in printcap file"); 13191553Srgrimes 13201553Srgrimes if (cgetstr(bp, "lp", &LP) == -1) 13211553Srgrimes LP = _PATH_DEFDEVLP; 13221553Srgrimes if (cgetstr(bp, "rp", &RP) == -1) 13231553Srgrimes RP = DEFLP; 13241553Srgrimes if (cgetstr(bp, "lo", &LO) == -1) 13251553Srgrimes LO = DEFLOCK; 13261553Srgrimes if (cgetstr(bp, "st", &ST) == -1) 13271553Srgrimes ST = DEFSTAT; 13281553Srgrimes if (cgetstr(bp, "lf", &LF) == -1) 13291553Srgrimes LF = _PATH_CONSOLE; 13301553Srgrimes if (cgetstr(bp, "sd", &SD) == -1) 13311553Srgrimes SD = _PATH_DEFSPOOL; 13321553Srgrimes if (cgetnum(bp, "du", &DU) < 0) 13331553Srgrimes DU = DEFUID; 13341553Srgrimes if (cgetstr(bp,"ff", &FF) == -1) 13351553Srgrimes FF = DEFFF; 13361553Srgrimes if (cgetnum(bp, "pw", &PW) < 0) 13371553Srgrimes PW = DEFWIDTH; 13381553Srgrimes sprintf(&width[2], "%d", PW); 13391553Srgrimes if (cgetnum(bp, "pl", &PL) < 0) 13401553Srgrimes PL = DEFLENGTH; 13411553Srgrimes sprintf(&length[2], "%d", PL); 13421553Srgrimes if (cgetnum(bp,"px", &PX) < 0) 13431553Srgrimes PX = 0; 13441553Srgrimes sprintf(&pxwidth[2], "%d", PX); 13451553Srgrimes if (cgetnum(bp, "py", &PY) < 0) 13461553Srgrimes PY = 0; 13471553Srgrimes sprintf(&pxlength[2], "%d", PY); 13481553Srgrimes cgetstr(bp, "rm", &RM); 13491553Srgrimes if (s = checkremote()) 13501553Srgrimes syslog(LOG_WARNING, s); 13511553Srgrimes 13521553Srgrimes cgetstr(bp, "af", &AF); 13531553Srgrimes cgetstr(bp, "of", &OF); 13541553Srgrimes cgetstr(bp, "if", &IF); 13551553Srgrimes cgetstr(bp, "rf", &RF); 13561553Srgrimes cgetstr(bp, "tf", &TF); 13571553Srgrimes cgetstr(bp, "nf", &NF); 13581553Srgrimes cgetstr(bp, "df", &DF); 13591553Srgrimes cgetstr(bp, "gf", &GF); 13601553Srgrimes cgetstr(bp, "vf", &VF); 13611553Srgrimes cgetstr(bp, "cf", &CF); 13621553Srgrimes cgetstr(bp, "tr", &TR); 136315032Ssef cgetstr(bp, "ms", &MS); 13641553Srgrimes 13651553Srgrimes RS = (cgetcap(bp, "rs", ':') != NULL); 13661553Srgrimes SF = (cgetcap(bp, "sf", ':') != NULL); 13671553Srgrimes SH = (cgetcap(bp, "sh", ':') != NULL); 13681553Srgrimes SB = (cgetcap(bp, "sb", ':') != NULL); 13691553Srgrimes HL = (cgetcap(bp, "hl", ':') != NULL); 13701553Srgrimes RW = (cgetcap(bp, "rw", ':') != NULL); 13711553Srgrimes 13721553Srgrimes cgetnum(bp, "br", &BR); 13731553Srgrimes 13741553Srgrimes tof = (cgetcap(bp, "fo", ':') == NULL); 13751553Srgrimes} 13761553Srgrimes 13771553Srgrimes/* 13781553Srgrimes * Acquire line printer or remote connection. 13791553Srgrimes */ 13801553Srgrimesstatic void 13811553Srgrimesopenpr() 13821553Srgrimes{ 138315648Sjoerg register int i; 138418569Sbde int dtablesize; 138515648Sjoerg char *cp; 13861553Srgrimes 138715648Sjoerg if (!remote && *LP) { 138815648Sjoerg if (cp = index(LP, '@')) 138915648Sjoerg opennet(cp); 139015648Sjoerg else 139115648Sjoerg opentty(); 139215648Sjoerg } else if (remote) { 139315648Sjoerg openrem(); 13941553Srgrimes } else { 13951553Srgrimes syslog(LOG_ERR, "%s: no line printer device or host name", 13961553Srgrimes printer); 13971553Srgrimes exit(1); 13981553Srgrimes } 139915648Sjoerg 14001553Srgrimes /* 14011553Srgrimes * Start up an output filter, if needed. 14021553Srgrimes */ 140324831Sbrian if (OF && !IF && !ofilter) { 14041553Srgrimes int p[2]; 14051553Srgrimes 14061553Srgrimes pipe(p); 140724831Sbrian if (remote) { 140824831Sbrian strcpy(tfile,TFILENAME); 140924831Sbrian tfd = mkstemp(tfile); 141024831Sbrian } 14111553Srgrimes if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 14121553Srgrimes dup2(p[0], 0); /* pipe is std in */ 141324831Sbrian /* tfile/printer is stdout */ 141424831Sbrian dup2(remote ? tfd : pfd, 1); 14158094Sjkh closelog(); 141618569Sbde for (i = 3, dtablesize = getdtablesize(); 141718569Sbde i < dtablesize; i++) 14181553Srgrimes (void) close(i); 14191553Srgrimes if ((cp = rindex(OF, '/')) == NULL) 14201553Srgrimes cp = OF; 14211553Srgrimes else 14221553Srgrimes cp++; 14231553Srgrimes execl(OF, cp, width, length, 0); 14241553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, OF); 14251553Srgrimes exit(1); 14261553Srgrimes } 14271553Srgrimes (void) close(p[0]); /* close input side */ 14281553Srgrimes ofd = p[1]; /* use pipe for output */ 14291553Srgrimes } else { 14301553Srgrimes ofd = pfd; 14311553Srgrimes ofilter = 0; 14321553Srgrimes } 14331553Srgrimes} 14341553Srgrimes 143515648Sjoerg/* 143615648Sjoerg * Printer connected directly to the network 143715648Sjoerg * or to a terminal server on the net 143815648Sjoerg */ 143915648Sjoergstatic void 144015648Sjoergopennet(cp) 144115648Sjoerg char *cp; 144215648Sjoerg{ 144315648Sjoerg register int i; 144415648Sjoerg int resp, port; 144515648Sjoerg char save_ch; 144615648Sjoerg 144715648Sjoerg save_ch = *cp; 144815648Sjoerg *cp = '\0'; 144915648Sjoerg port = atoi(LP); 145015648Sjoerg if (port <= 0) { 145115648Sjoerg syslog(LOG_ERR, "%s: bad port number: %s", printer, LP); 145215648Sjoerg exit(1); 145315648Sjoerg } 145415648Sjoerg *cp++ = save_ch; 145515648Sjoerg 145615648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 145715648Sjoerg resp = -1; 145815648Sjoerg pfd = getport(cp, port); 145915648Sjoerg if (pfd < 0 && errno == ECONNREFUSED) 146015648Sjoerg resp = 1; 146115648Sjoerg else if (pfd >= 0) { 146215648Sjoerg /* 146315648Sjoerg * need to delay a bit for rs232 lines 146415648Sjoerg * to stabilize in case printer is 146515648Sjoerg * connected via a terminal server 146615648Sjoerg */ 146715648Sjoerg delay(500); 146815648Sjoerg break; 146915648Sjoerg } 147015648Sjoerg if (i == 1) { 147115648Sjoerg if (resp < 0) 147215648Sjoerg pstatus("waiting for %s to come up", LP); 147315648Sjoerg else 147415648Sjoerg pstatus("waiting for access to printer on %s", LP); 147515648Sjoerg } 147615648Sjoerg sleep(i); 147715648Sjoerg } 147815648Sjoerg pstatus("sending to %s port %d", cp, port); 147915648Sjoerg} 148015648Sjoerg 148115648Sjoerg/* 148215648Sjoerg * Printer is connected to an RS232 port on this host 148315648Sjoerg */ 148415648Sjoergstatic void 148515648Sjoergopentty() 148615648Sjoerg{ 148715648Sjoerg register int i; 148815648Sjoerg int resp, port; 148915648Sjoerg 149015648Sjoerg for (i = 1; ; i = i < 32 ? i << 1 : i) { 149115648Sjoerg pfd = open(LP, RW ? O_RDWR : O_WRONLY); 149215648Sjoerg if (pfd >= 0) { 149315648Sjoerg delay(500); 149415648Sjoerg break; 149515648Sjoerg } 149615648Sjoerg if (errno == ENOENT) { 149715648Sjoerg syslog(LOG_ERR, "%s: %m", LP); 149815648Sjoerg exit(1); 149915648Sjoerg } 150015648Sjoerg if (i == 1) 150115648Sjoerg pstatus("waiting for %s to become ready (offline ?)", 150215648Sjoerg printer); 150315648Sjoerg sleep(i); 150415648Sjoerg } 150515648Sjoerg if (isatty(pfd)) 150615648Sjoerg setty(); 150715648Sjoerg pstatus("%s is ready and printing", printer); 150815648Sjoerg} 150915648Sjoerg 151015648Sjoerg/* 151115648Sjoerg * Printer is on a remote host 151215648Sjoerg */ 151315648Sjoergstatic void 151415648Sjoergopenrem() 151515648Sjoerg{ 151615648Sjoerg register int i, n; 151715648Sjoerg int resp, port; 151815648Sjoerg 151915648Sjoerg for (i = 1; ; i = i < 256 ? i << 1 : i) { 152015648Sjoerg resp = -1; 152115648Sjoerg pfd = getport(RM, 0); 152215648Sjoerg if (pfd >= 0) { 152315648Sjoerg (void) sprintf(line, "\2%s\n", RP); 152415648Sjoerg n = strlen(line); 152515648Sjoerg if (write(pfd, line, n) == n && 152615648Sjoerg (resp = response()) == '\0') 152715648Sjoerg break; 152815648Sjoerg (void) close(pfd); 152915648Sjoerg } 153015648Sjoerg if (i == 1) { 153115648Sjoerg if (resp < 0) 153215648Sjoerg pstatus("waiting for %s to come up", RM); 153315648Sjoerg else { 153415648Sjoerg pstatus("waiting for queue to be enabled on %s", 153515648Sjoerg RM); 153615648Sjoerg i = 256; 153715648Sjoerg } 153815648Sjoerg } 153915648Sjoerg sleep(i); 154015648Sjoerg } 154115648Sjoerg pstatus("sending to %s", RM); 154215648Sjoerg} 154315648Sjoerg 15441553Srgrimesstruct bauds { 15451553Srgrimes int baud; 15461553Srgrimes int speed; 15471553Srgrimes} bauds[] = { 15481553Srgrimes 50, B50, 15491553Srgrimes 75, B75, 15501553Srgrimes 110, B110, 15511553Srgrimes 134, B134, 15521553Srgrimes 150, B150, 15531553Srgrimes 200, B200, 15541553Srgrimes 300, B300, 15551553Srgrimes 600, B600, 15561553Srgrimes 1200, B1200, 15571553Srgrimes 1800, B1800, 15581553Srgrimes 2400, B2400, 15591553Srgrimes 4800, B4800, 15601553Srgrimes 9600, B9600, 15611553Srgrimes 19200, EXTA, 15621553Srgrimes 38400, EXTB, 15639821Swpaul 57600, B57600, 15649821Swpaul 115200, B115200, 15651553Srgrimes 0, 0 15661553Srgrimes}; 15671553Srgrimes 15681553Srgrimes/* 15691553Srgrimes * setup tty lines. 15701553Srgrimes */ 15711553Srgrimesstatic void 15721553Srgrimessetty() 15731553Srgrimes{ 157415032Ssef struct termios ttybuf; 157515032Ssef struct bauds *bp; 15761553Srgrimes 15771553Srgrimes if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 15781553Srgrimes syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 15791553Srgrimes exit(1); 15801553Srgrimes } 158115032Ssef if (tcgetattr(pfd, &ttybuf) < 0) { 158215032Ssef syslog(LOG_ERR, "%s: tcgetattr: %m", printer); 15831553Srgrimes exit(1); 15841553Srgrimes } 15851553Srgrimes if (BR > 0) { 15861553Srgrimes for (bp = bauds; bp->baud; bp++) 15871553Srgrimes if (BR == bp->baud) 15881553Srgrimes break; 15891553Srgrimes if (!bp->baud) { 15901553Srgrimes syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 15911553Srgrimes exit(1); 15921553Srgrimes } 159315032Ssef cfsetspeed(&ttybuf, bp->speed); 15941553Srgrimes } 159515032Ssef if (MS) { 159615032Ssef char *s = strdup(MS), *tmp; 159715032Ssef 159815032Ssef while (tmp = strsep (&s, ",")) { 159915032Ssef msearch(tmp, &ttybuf); 16001553Srgrimes } 16011553Srgrimes } 160215032Ssef if (MS || (BR > 0)) { 160315032Ssef if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 160415032Ssef syslog(LOG_ERR, "%s: tcsetattr: %m", printer); 16051553Srgrimes } 16061553Srgrimes } 16071553Srgrimes} 16081553Srgrimes 16091553Srgrimes#if __STDC__ 16101553Srgrimes#include <stdarg.h> 16111553Srgrimes#else 16121553Srgrimes#include <varargs.h> 16131553Srgrimes#endif 16141553Srgrimes 161515648Sjoergstatic void 16161553Srgrimes#if __STDC__ 16171553Srgrimespstatus(const char *msg, ...) 16181553Srgrimes#else 16191553Srgrimespstatus(msg, va_alist) 16201553Srgrimes char *msg; 16211553Srgrimes va_dcl 16221553Srgrimes#endif 16231553Srgrimes{ 16241553Srgrimes register int fd; 16251553Srgrimes char buf[BUFSIZ]; 16261553Srgrimes va_list ap; 16271553Srgrimes#if __STDC__ 16281553Srgrimes va_start(ap, msg); 16291553Srgrimes#else 16301553Srgrimes va_start(ap); 16311553Srgrimes#endif 16321553Srgrimes 16331553Srgrimes umask(0); 16341553Srgrimes fd = open(ST, O_WRONLY|O_CREAT, 0664); 16351553Srgrimes if (fd < 0 || flock(fd, LOCK_EX) < 0) { 16361553Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, ST); 16371553Srgrimes exit(1); 16381553Srgrimes } 16391553Srgrimes ftruncate(fd, 0); 16401553Srgrimes (void)vsnprintf(buf, sizeof(buf), msg, ap); 16411553Srgrimes va_end(ap); 16421553Srgrimes strcat(buf, "\n"); 16431553Srgrimes (void) write(fd, buf, strlen(buf)); 16441553Srgrimes (void) close(fd); 16451553Srgrimes} 1646