printjob.c revision 83684
1105197Ssam/* 2105197Ssam * Copyright (c) 1983, 1993 3139823Simp * The Regents of the University of California. All rights reserved. 4105197Ssam * 5105197Ssam * 6105197Ssam * Redistribution and use in source and binary forms, with or without 7105197Ssam * modification, are permitted provided that the following conditions 8105197Ssam * are met: 9105197Ssam * 1. Redistributions of source code must retain the above copyright 10105197Ssam * notice, this list of conditions and the following disclaimer. 11105197Ssam * 2. Redistributions in binary form must reproduce the above copyright 12105197Ssam * notice, this list of conditions and the following disclaimer in the 13105197Ssam * documentation and/or other materials provided with the distribution. 14105197Ssam * 3. All advertising materials mentioning features or use of this software 15105197Ssam * must display the following acknowledgement: 16105197Ssam * This product includes software developed by the University of 17105197Ssam * California, Berkeley and its contributors. 18105197Ssam * 4. Neither the name of the University nor the names of its contributors 19105197Ssam * may be used to endorse or promote products derived from this software 20105197Ssam * without specific prior written permission. 21105197Ssam * 22105197Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23105197Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24105197Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25105197Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26105197Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27105197Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28105197Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29105197Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30105197Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31105197Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32105197Ssam * SUCH DAMAGE. 33105197Ssam */ 34105197Ssam 35105197Ssam#ifndef lint 36105197Ssamstatic const char copyright[] = 37105197Ssam"@(#) Copyright (c) 1983, 1993\n\ 38105197Ssam The Regents of the University of California. All rights reserved.\n"; 39105197Ssam#endif /* not lint */ 40105197Ssam 41105197Ssam#ifndef lint 42105197Ssam/* 43105197Ssamstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 44105197Ssam*/ 45105197Ssamstatic const char rcsid[] = 46105197Ssam "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 83684 2001-09-20 01:04:50Z gad $"; 47105197Ssam#endif /* not lint */ 48105197Ssam 49105197Ssam 50105197Ssam/* 51195699Srwatson * printjob -- print jobs in the queue. 52105197Ssam * 53105197Ssam * NOTE: the lock file is used to pass information to lpq and lprm. 54105197Ssam * it does not need to be removed because file locks are dynamic. 55105197Ssam */ 56105197Ssam 57105197Ssam#include <sys/param.h> 58105197Ssam#include <sys/wait.h> 59105197Ssam#include <sys/stat.h> 60105197Ssam#include <sys/types.h> 61105197Ssam 62105197Ssam#include <pwd.h> 63105197Ssam#include <unistd.h> 64105197Ssam#include <signal.h> 65105197Ssam#include <syslog.h> 66105197Ssam#include <fcntl.h> 67105197Ssam#include <dirent.h> 68105197Ssam#include <errno.h> 69105197Ssam#include <stdio.h> 70105197Ssam#include <string.h> 71105197Ssam#include <stdlib.h> 72105197Ssam#include <sys/ioctl.h> 73105197Ssam#include <termios.h> 74105197Ssam#include <time.h> 75105197Ssam#include "lp.h" 76105197Ssam#include "lp.local.h" 77105197Ssam#include "pathnames.h" 78105197Ssam#include "extern.h" 79105197Ssam 80105197Ssam#define DORETURN 0 /* dofork should return "can't fork" error */ 81105197Ssam#define DOABORT 1 /* dofork should just die if fork() fails */ 82105197Ssam 83105197Ssam/* 84158704Spjd * Error tokens 85158704Spjd */ 86105197Ssam#define REPRINT -2 87218794Svanhu#define ERROR -1 88105197Ssam#define OK 0 89195699Srwatson#define FATALERR 1 90195699Srwatson#define NOACCT 2 91253088Sae#define FILTERERR 3 92253088Sae#define ACCESS 4 93105197Ssam 94253088Saestatic dev_t fdev; /* device of file pointed to by symlink */ 95253088Saestatic ino_t fino; /* inode of file pointed to by symlink */ 96253088Saestatic FILE *cfp; /* control file */ 97253088Saestatic int child; /* id of any filters */ 98221129Sbzstatic int job_dfcnt; /* count of datafiles in current user job */ 99105197Ssamstatic int lfd; /* lock file descriptor */ 100195699Srwatsonstatic int ofd; /* output filter file descriptor */ 101195699Srwatsonstatic int ofilter; /* id of output filter, if any */ 102195699Srwatsonstatic int tfd = -1; /* output filter temp file output */ 103195699Srwatsonstatic int pfd; /* prstatic inter file descriptor */ 104253088Saestatic int pid; /* pid of lpd process */ 105253088Saestatic int prchild; /* id of pr process */ 106221129Sbzstatic char title[80]; /* ``pr'' title */ 107105197Ssamstatic char locale[80]; /* ``pr'' locale */ 108105197Ssam 109105197Ssam/* these two are set from pp->daemon_user, but only if they are needed */ 110105197Ssamstatic char *daemon_uname; /* set from pwd->pw_name */ 111105197Ssamstatic int daemon_defgid; 112105197Ssam 113218794Svanhustatic char class[32]; /* classification field */ 114218794Svanhustatic char origin_host[MAXHOSTNAMELEN]; /* user's host machine */ 115218794Svanhu /* indentation size in static characters */ 116218794Svanhustatic char indent[10] = "-i0"; 117218794Svanhustatic char jobname[100]; /* job or file name */ 118218794Svanhustatic char length[10] = "-l"; /* page length in lines */ 119218794Svanhustatic char logname[32]; /* user's login name */ 120218794Svanhustatic char pxlength[10] = "-y"; /* page length in pixels */ 121218794Svanhustatic char pxwidth[10] = "-x"; /* page width in pixels */ 122218794Svanhu/* tempstderr is the filename used to catch stderr from exec-ing filters */ 123218794Svanhustatic char tempstderr[] = "errs.XXXXXXX"; 124218794Svanhustatic char width[10] = "-w"; /* page width in static characters */ 125218794Svanhu#define TFILENAME "fltXXXXXX" 126218794Svanhustatic char tfile[] = TFILENAME; /* file name for filter output */ 127218794Svanhu 128218794Svanhustatic void abortpr(int _signo); 129218794Svanhustatic void alarmhandler(int _signo); 130218794Svanhustatic void banner(struct printer *_pp, char *_name1, char *_name2); 131218794Svanhustatic int dofork(const struct printer *_pp, int _action); 132218794Svanhustatic int dropit(int _c); 133218794Svanhustatic void init(struct printer *_pp); 134105197Ssamstatic void openpr(const struct printer *_pp); 135105197Ssamstatic void opennet(const struct printer *_pp); 136105197Ssamstatic void opentty(const struct printer *_pp); 137105197Ssamstatic void openrem(const struct printer *pp); 138105197Ssamstatic int print(struct printer *_pp, int _format, char *_file); 139105197Ssamstatic int printit(struct printer *_pp, char *_file); 140171133Sgnnstatic void pstatus(const struct printer *_pp, const char *_msg, ...) 141105197Ssam __printflike(2, 3); 142105197Ssamstatic char response(const struct printer *_pp); 143105197Ssamstatic void scan_out(struct printer *_pp, int _scfd, char *_scsp, 144105197Ssam int _dlm); 145105197Ssamstatic char *scnline(int _key, char *_p, int _c); 146158704Spjdstatic int sendfile(struct printer *_pp, int _type, char *_file, 147105197Ssam char _format); 148158704Spjdstatic int sendit(struct printer *_pp, char *_file); 149105197Ssamstatic void sendmail(struct printer *_pp, char *_user, int _bombed); 150158704Spjdstatic void setty(const struct printer *_pp); 151105197Ssam 152105197Ssamvoid 153105197Ssamprintjob(struct printer *pp) 154105197Ssam{ 155105197Ssam struct stat stb; 156105197Ssam register struct jobqueue *q, **qp; 157105197Ssam struct jobqueue **queue; 158105197Ssam register int i, nitems; 159105197Ssam off_t pidoff; 160105197Ssam int errcnt, jobcount, tempfd; 161105197Ssam 162105197Ssam jobcount = 0; 163105197Ssam init(pp); /* set up capabilities */ 164105197Ssam (void) write(1, "", 1); /* ack that daemon is started */ 165105197Ssam (void) close(2); /* set up log file */ 166105197Ssam if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 167105197Ssam syslog(LOG_ERR, "%s: %m", pp->log_file); 168105197Ssam (void) open(_PATH_DEVNULL, O_WRONLY); 169105197Ssam } 170105197Ssam setgid(getegid()); 171105197Ssam pid = getpid(); /* for use with lprm */ 172120585Ssam setpgrp(0, pid); 173105197Ssam 174105197Ssam /* 175105197Ssam * At initial lpd startup, printjob may be called with various 176105197Ssam * signal handlers in effect. After that initial startup, any 177105197Ssam * calls to printjob will have a *different* set of signal-handlers 178105197Ssam * in effect. Make sure all handlers are the ones we want. 179105197Ssam */ 180105197Ssam signal(SIGCHLD, SIG_DFL); 181105197Ssam signal(SIGHUP, abortpr); 182105197Ssam signal(SIGINT, abortpr); 183105197Ssam signal(SIGQUIT, abortpr); 184105197Ssam signal(SIGTERM, abortpr); 185105197Ssam 186105197Ssam /* 187105197Ssam * uses short form file names 188105197Ssam */ 189105197Ssam if (chdir(pp->spool_dir) < 0) { 190105197Ssam syslog(LOG_ERR, "%s: %m", pp->spool_dir); 191105197Ssam exit(1); 192105197Ssam } 193105197Ssam if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 194120585Ssam exit(0); /* printing disabled */ 195120585Ssam lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 196105197Ssam LOCK_FILE_MODE); 197105197Ssam if (lfd < 0) { 198105197Ssam if (errno == EWOULDBLOCK) /* active daemon present */ 199105197Ssam exit(0); 200105197Ssam syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 201105197Ssam exit(1); 202105197Ssam } 203105197Ssam /* turn off non-blocking mode (was turned on for lock effects only) */ 204105197Ssam if (fcntl(lfd, F_SETFL, 0) < 0) { 205120585Ssam syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 206120585Ssam exit(1); 207105197Ssam } 208105197Ssam ftruncate(lfd, 0); 209105197Ssam /* 210105197Ssam * write process id for others to know 211105197Ssam */ 212120585Ssam sprintf(line, "%u\n", pid); 213120585Ssam pidoff = i = strlen(line); 214105197Ssam if (write(lfd, line, i) != i) { 215105197Ssam syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 216105197Ssam exit(1); 217105197Ssam } 218120585Ssam /* 219120585Ssam * search the spool directory for work and sort by queue order. 220105197Ssam */ 221105197Ssam if ((nitems = getq(pp, &queue)) < 0) { 222105197Ssam syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 223105197Ssam pp->spool_dir); 224105197Ssam exit(1); 225105197Ssam } 226105197Ssam if (nitems == 0) /* no work to do */ 227105197Ssam exit(0); 228105197Ssam if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 229105197Ssam if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 230105197Ssam syslog(LOG_ERR, "%s: %s: %m", pp->printer, 231157123Sgnn pp->lock_file); 232158704Spjd } 233105197Ssam 234105197Ssam /* create a file which will be used to hold stderr from filters */ 235105197Ssam if ((tempfd = mkstemp(tempstderr)) == -1) { 236105197Ssam syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 237105197Ssam tempstderr); 238105197Ssam exit(1); 239105197Ssam } 240105197Ssam if ((i = fchmod(tempfd, 0664)) == -1) { 241105197Ssam syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 242105197Ssam tempstderr); 243105197Ssam exit(1); 244105197Ssam } 245105197Ssam /* lpd doesn't need it to be open, it just needs it to exist */ 246105197Ssam close(tempfd); 247105197Ssam 248181803Sbz openpr(pp); /* open printer or remote */ 249105197Ssamagain: 250105197Ssam /* 251105197Ssam * we found something to do now do it -- 252105197Ssam * write the name of the current control file into the lock file 253105197Ssam * so the spool queue program can tell what we're working on 254105197Ssam */ 255105197Ssam for (qp = queue; nitems--; free((char *) q)) { 256105197Ssam q = *qp++; 257105197Ssam if (stat(q->job_cfname, &stb) < 0) 258105197Ssam continue; 259105197Ssam errcnt = 0; 260105197Ssam restart: 261105197Ssam (void) lseek(lfd, pidoff, 0); 262157123Sgnn (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 263105197Ssam i = strlen(line); 264105197Ssam if (write(lfd, line, i) != i) 265105197Ssam syslog(LOG_ERR, "%s: %s: %m", pp->printer, 266105197Ssam pp->lock_file); 267105197Ssam if (!pp->remote) 268105197Ssam i = printit(pp, q->job_cfname); 269105197Ssam else 270105197Ssam i = sendit(pp, q->job_cfname); 271105197Ssam /* 272105197Ssam * Check to see if we are supposed to stop printing or 273105197Ssam * if we are to rebuild the queue. 274105197Ssam */ 275105197Ssam if (fstat(lfd, &stb) == 0) { 276105197Ssam /* stop printing before starting next job? */ 277105197Ssam if (stb.st_mode & LFM_PRINT_DIS) 278105197Ssam goto done; 279105197Ssam /* rebuild queue (after lpc topq) */ 280105197Ssam if (stb.st_mode & LFM_RESET_QUE) { 281105197Ssam for (free(q); nitems--; free(q)) 282105197Ssam q = *qp++; 283105197Ssam if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 284105197Ssam < 0) 285105197Ssam syslog(LOG_WARNING, "%s: %s: %m", 286105197Ssam pp->printer, pp->lock_file); 287105197Ssam break; 288105197Ssam } 289105197Ssam } 290105197Ssam if (i == OK) /* all files of this job printed */ 291105197Ssam jobcount++; 292105197Ssam else if (i == REPRINT && ++errcnt < 5) { 293105197Ssam /* try reprinting the job */ 294105197Ssam syslog(LOG_INFO, "restarting %s", pp->printer); 295105197Ssam if (ofilter > 0) { 296105197Ssam kill(ofilter, SIGCONT); /* to be sure */ 297105197Ssam (void) close(ofd); 298105197Ssam while ((i = wait(NULL)) > 0 && i != ofilter) 299105197Ssam ; 300105197Ssam if (i < 0) 301120585Ssam syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m", 302105197Ssam pp->printer, ofilter); 303105197Ssam ofilter = 0; 304105197Ssam } 305105197Ssam (void) close(pfd); /* close printer */ 306105197Ssam if (ftruncate(lfd, pidoff) < 0) 307181803Sbz syslog(LOG_WARNING, "%s: %s: %m", 308105197Ssam pp->printer, pp->lock_file); 309105197Ssam openpr(pp); /* try to reopen printer */ 310105197Ssam goto restart; 311105197Ssam } else { 312241919Sglebius syslog(LOG_WARNING, "%s: job could not be %s (%s)", 313241919Sglebius pp->printer, 314241919Sglebius pp->remote ? "sent to remote host" : "printed", 315241919Sglebius q->job_cfname); 316105197Ssam if (i == REPRINT) { 317105197Ssam /* ensure we don't attempt this job again */ 318105197Ssam (void) unlink(q->job_cfname); 319105197Ssam q->job_cfname[0] = 'd'; 320105197Ssam (void) unlink(q->job_cfname); 321105197Ssam if (logname[0]) 322105197Ssam sendmail(pp, logname, FATALERR); 323105197Ssam } 324105197Ssam } 325120585Ssam } 326120585Ssam free(queue); 327105197Ssam /* 328105197Ssam * search the spool directory for more work. 329105197Ssam */ 330105197Ssam if ((nitems = getq(pp, &queue)) < 0) { 331105197Ssam syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 332105197Ssam pp->spool_dir); 333105197Ssam exit(1); 334105197Ssam } 335105197Ssam if (nitems == 0) { /* no more work to do */ 336105197Ssam done: 337105197Ssam if (jobcount > 0) { /* jobs actually printed */ 338105197Ssam if (!pp->no_formfeed && !pp->tof) 339105197Ssam (void) write(ofd, pp->form_feed, 340105197Ssam strlen(pp->form_feed)); 341105197Ssam if (pp->trailer != NULL) /* output trailer */ 342105197Ssam (void) write(ofd, pp->trailer, 343105197Ssam strlen(pp->trailer)); 344105197Ssam } 345105197Ssam (void) close(ofd); 346105197Ssam (void) wait(NULL); 347105197Ssam (void) unlink(tempstderr); 348120585Ssam exit(0); 349120585Ssam } 350120585Ssam goto again; 351105197Ssam} 352105197Ssam 353105197Ssamchar fonts[4][50]; /* fonts for troff */ 354105197Ssam 355105197Ssamchar ifonts[4][40] = { 356105197Ssam _PATH_VFONTR, 357105197Ssam _PATH_VFONTI, 358105197Ssam _PATH_VFONTB, 359105197Ssam _PATH_VFONTS, 360105197Ssam}; 361105197Ssam 362105197Ssam/* 363120585Ssam * The remaining part is the reading of the control file (cf) 364120585Ssam * and performing the various actions. 365120585Ssam */ 366105197Ssamstatic int 367105197Ssamprintit(struct printer *pp, char *file) 368105197Ssam{ 369105197Ssam register int i; 370105197Ssam char *cp; 371105197Ssam int bombed, didignorehdr; 372105197Ssam 373105197Ssam bombed = OK; 374105197Ssam didignorehdr = 0; 375105197Ssam /* 376105197Ssam * open control file; ignore if no longer there. 377105197Ssam */ 378105197Ssam if ((cfp = fopen(file, "r")) == NULL) { 379105197Ssam syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 380105197Ssam return(OK); 381105197Ssam } 382105197Ssam /* 383105197Ssam * Reset troff fonts. 384105197Ssam */ 385105197Ssam for (i = 0; i < 4; i++) 386105197Ssam strcpy(fonts[i], ifonts[i]); 387105197Ssam sprintf(&width[2], "%ld", pp->page_width); 388105197Ssam strcpy(indent+2, "0"); 389120585Ssam 390120585Ssam /* initialize job-specific count of datafiles processed */ 391120585Ssam job_dfcnt = 0; 392105197Ssam 393105197Ssam /* 394105197Ssam * read the control file for work to do 395105197Ssam * 396105197Ssam * file format -- first character in the line is a command 397105197Ssam * rest of the line is the argument. 398105197Ssam * valid commands are: 399105197Ssam * 400105197Ssam * S -- "stat info" for symbolic link protection 401105197Ssam * J -- "job name" on banner page 402105197Ssam * C -- "class name" on banner page 403105197Ssam * L -- "literal" user's name to print on banner 404105197Ssam * T -- "title" for pr 405120585Ssam * H -- "host name" of machine where lpr was done 406120585Ssam * P -- "person" user's login name 407105197Ssam * I -- "indent" amount to indent output 408105197Ssam * R -- laser dpi "resolution" 409105197Ssam * f -- "file name" name of text file to print 410105197Ssam * l -- "file name" text file with control chars 411105197Ssam * o -- "file name" postscript file, according to 412105197Ssam * the RFC. Here it is treated like an 'f'. 413105197Ssam * p -- "file name" text file to print with pr(1) 414105197Ssam * t -- "file name" troff(1) file to print 415105197Ssam * n -- "file name" ditroff(1) file to print 416105197Ssam * d -- "file name" dvi file to print 417105197Ssam * g -- "file name" plot(1G) file to print 418105197Ssam * v -- "file name" plain raster file to print 419105197Ssam * c -- "file name" cifplot file to print 420105197Ssam * 1 -- "R font file" for troff 421105197Ssam * 2 -- "I font file" for troff 422105197Ssam * 3 -- "B font file" for troff 423120585Ssam * 4 -- "S font file" for troff 424105197Ssam * N -- "name" of file (used by lpq) 425105197Ssam * U -- "unlink" name of file to remove 426105197Ssam * (after we print it. (Pass 2 only)). 427105197Ssam * M -- "mail" to user when done printing 428105197Ssam * Z -- "locale" for pr 429105197Ssam * 430105197Ssam * getline reads a line and expands tabs to blanks 431105197Ssam */ 432105197Ssam 433105197Ssam /* pass 1 */ 434105197Ssam 435105197Ssam while (getline(cfp)) 436105197Ssam switch (line[0]) { 437105197Ssam case 'H': 438105197Ssam strlcpy(origin_host, line + 1, sizeof(origin_host)); 439105197Ssam if (class[0] == '\0') { 440105197Ssam strlcpy(class, line+1, sizeof(class)); 441105197Ssam } 442105197Ssam continue; 443105197Ssam 444105197Ssam case 'P': 445105197Ssam strlcpy(logname, line + 1, sizeof(logname)); 446105197Ssam if (pp->restricted) { /* restricted */ 447105197Ssam if (getpwnam(logname) == NULL) { 448105197Ssam bombed = NOACCT; 449120585Ssam sendmail(pp, line+1, bombed); 450120585Ssam goto pass2; 451105197Ssam } 452105197Ssam } 453105197Ssam continue; 454105197Ssam 455105197Ssam case 'S': 456105197Ssam cp = line+1; 457105197Ssam i = 0; 458105197Ssam while (*cp >= '0' && *cp <= '9') 459105197Ssam i = i * 10 + (*cp++ - '0'); 460105197Ssam fdev = i; 461105197Ssam cp++; 462105197Ssam i = 0; 463105197Ssam while (*cp >= '0' && *cp <= '9') 464105197Ssam i = i * 10 + (*cp++ - '0'); 465105197Ssam fino = i; 466105197Ssam continue; 467105197Ssam 468105197Ssam case 'J': 469105197Ssam if (line[1] != '\0') { 470105197Ssam strlcpy(jobname, line + 1, sizeof(jobname)); 471105197Ssam } else 472105197Ssam strcpy(jobname, " "); 473105197Ssam continue; 474105197Ssam 475105197Ssam case 'C': 476105197Ssam if (line[1] != '\0') 477105197Ssam strlcpy(class, line + 1, sizeof(class)); 478105197Ssam else if (class[0] == '\0') { 479105197Ssam /* XXX - why call gethostname instead of 480105197Ssam * just strlcpy'ing local_host? */ 481105197Ssam gethostname(class, sizeof(class)); 482105197Ssam class[sizeof(class) - 1] = '\0'; 483105197Ssam } 484105197Ssam continue; 485105197Ssam 486105197Ssam case 'T': /* header title for pr */ 487105197Ssam strlcpy(title, line + 1, sizeof(title)); 488105197Ssam continue; 489105197Ssam 490105197Ssam case 'L': /* identification line */ 491105197Ssam if (!pp->no_header && !pp->header_last) 492105197Ssam banner(pp, line+1, jobname); 493105197Ssam continue; 494105197Ssam 495105197Ssam case '1': /* troff fonts */ 496105197Ssam case '2': 497105197Ssam case '3': 498184205Sdes case '4': 499105197Ssam if (line[1] != '\0') { 500105197Ssam strlcpy(fonts[line[0]-'1'], line + 1, 501105197Ssam (size_t)50); 502105197Ssam } 503105197Ssam continue; 504105197Ssam 505105197Ssam case 'W': /* page width */ 506105197Ssam strlcpy(width+2, line + 1, sizeof(width) - 2); 507105197Ssam continue; 508105197Ssam 509105197Ssam case 'I': /* indent amount */ 510105197Ssam strlcpy(indent+2, line + 1, sizeof(indent) - 2); 511105197Ssam continue; 512105197Ssam 513105197Ssam case 'Z': /* locale for pr */ 514105197Ssam strlcpy(locale, line + 1, sizeof(locale)); 515105197Ssam locale[sizeof(locale) - 1] = '\0'; 516105197Ssam continue; 517105197Ssam 518184205Sdes default: /* some file to print */ 519105197Ssam /* only lowercase cmd-codes include a file-to-print */ 520105197Ssam if ((line[0] < 'a') || (line[0] > 'z')) { 521105197Ssam /* ignore any other lines */ 522105197Ssam if (lflag <= 1) 523105197Ssam continue; 524105197Ssam if (!didignorehdr) { 525105197Ssam syslog(LOG_INFO, "%s: in %s :", 526105197Ssam pp->printer, file); 527105197Ssam didignorehdr = 1; 528105197Ssam } 529105197Ssam syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 530105197Ssam pp->printer, line[0], &line[1]); 531105197Ssam continue; 532105197Ssam } 533105197Ssam i = print(pp, line[0], line+1); 534105197Ssam switch (i) { 535105197Ssam case ERROR: 536105197Ssam if (bombed == OK) 537105197Ssam bombed = FATALERR; 538105197Ssam break; 539120585Ssam case REPRINT: 540120585Ssam (void) fclose(cfp); 541105197Ssam return(REPRINT); 542184205Sdes case FILTERERR: 543105197Ssam case ACCESS: 544105197Ssam bombed = i; 545105197Ssam sendmail(pp, logname, bombed); 546105197Ssam } 547105197Ssam title[0] = '\0'; 548105197Ssam continue; 549105197Ssam 550105197Ssam case 'N': 551105197Ssam case 'U': 552105197Ssam case 'M': 553105197Ssam case 'R': 554105197Ssam continue; 555105197Ssam } 556105197Ssam 557105197Ssam /* pass 2 */ 558105197Ssam 559105197Ssampass2: 560105197Ssam fseek(cfp, 0L, 0); 561105197Ssam while (getline(cfp)) 562105197Ssam switch (line[0]) { 563105197Ssam case 'L': /* identification line */ 564105197Ssam if (!pp->no_header && pp->header_last) 565105197Ssam banner(pp, line+1, jobname); 566105197Ssam continue; 567105197Ssam 568105197Ssam case 'M': 569105197Ssam if (bombed < NOACCT) /* already sent if >= NOACCT */ 570105197Ssam sendmail(pp, line+1, bombed); 571105197Ssam continue; 572105197Ssam 573105197Ssam case 'U': 574105197Ssam if (strchr(line+1, '/')) 575105197Ssam continue; 576105197Ssam (void) unlink(line+1); 577105197Ssam } 578120585Ssam /* 579120585Ssam * clean-up in case another control file exists 580120585Ssam */ 581120585Ssam (void) fclose(cfp); 582105197Ssam (void) unlink(file); 583105197Ssam return(bombed == OK ? OK : ERROR); 584105197Ssam} 585105197Ssam 586105197Ssam/* 587105197Ssam * Print a file. 588105197Ssam * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 589105197Ssam * Return -1 if a non-recoverable error occured, 590252028Sae * 2 if the filter detected some errors (but printed the job anyway), 591105197Ssam * 1 if we should try to reprint this job and 592105197Ssam * 0 if all is well. 593105197Ssam * Note: all filters take stdin as the file, stdout as the printer, 594105197Ssam * stderr as the log file, and must not ignore SIGINT. 595105197Ssam */ 596105197Ssamstatic int 597252028Saeprint(struct printer *pp, int format, char *file) 598120585Ssam{ 599105197Ssam register int n, i; 600105197Ssam register char *prog; 601105197Ssam int fi, fo; 602105197Ssam FILE *fp; 603105197Ssam char *av[15], buf[BUFSIZ]; 604105197Ssam int pid, p[2], stopped; 605105197Ssam union wait status; 606105197Ssam struct stat stb; 607105197Ssam 608105197Ssam if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 609120585Ssam syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 610120585Ssam pp->printer, file, format); 611105197Ssam return(ERROR); 612105197Ssam } 613105197Ssam /* 614252028Sae * Check to see if data file is a symbolic link. If so, it should 615105197Ssam * still point to the same file or someone is trying to print 616105197Ssam * something he shouldn't. 617105197Ssam */ 618252028Sae if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 619105197Ssam (stb.st_dev != fdev || stb.st_ino != fino)) 620105197Ssam return(ACCESS); 621105197Ssam 622105197Ssam job_dfcnt++; /* increment datafile counter for this job */ 623120585Ssam stopped = 0; /* output filter is not stopped */ 624252028Sae 625105197Ssam /* everything seems OK, start it up */ 626105197Ssam if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 627105197Ssam (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 628105197Ssam pp->tof = 1; 629105197Ssam } 630120585Ssam if (pp->filters[LPF_INPUT] == NULL 631105197Ssam && (format == 'f' || format == 'l' || format == 'o')) { 632105197Ssam pp->tof = 0; 633105197Ssam while ((n = read(fi, buf, BUFSIZ)) > 0) 634105197Ssam if (write(ofd, buf, n) != n) { 635105197Ssam (void) close(fi); 636105197Ssam return(REPRINT); 637105197Ssam } 638105197Ssam (void) close(fi); 639157123Sgnn return(OK); 640105197Ssam } 641105197Ssam switch (format) { 642105197Ssam case 'p': /* print file using 'pr' */ 643105197Ssam if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 644105197Ssam prog = _PATH_PR; 645105197Ssam i = 0; 646105197Ssam av[i++] = "pr"; 647105197Ssam av[i++] = width; 648105197Ssam av[i++] = length; 649105197Ssam av[i++] = "-h"; 650105197Ssam av[i++] = *title ? title : " "; 651105197Ssam av[i++] = "-L"; 652105197Ssam av[i++] = *locale ? locale : "C"; 653105197Ssam av[i++] = "-F"; 654105197Ssam av[i] = 0; 655105197Ssam fo = ofd; 656105197Ssam goto start; 657105197Ssam } 658105197Ssam pipe(p); 659105197Ssam if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 660105197Ssam dup2(fi, 0); /* file is stdin */ 661105197Ssam dup2(p[1], 1); /* pipe is stdout */ 662105197Ssam closelog(); 663120585Ssam closeallfds(3); 664252028Sae execl(_PATH_PR, "pr", width, length, 665105197Ssam "-h", *title ? title : " ", 666105197Ssam "-L", *locale ? locale : "C", 667105197Ssam "-F", (char *)0); 668105197Ssam syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 669105197Ssam exit(2); 670105197Ssam } 671105197Ssam (void) close(p[1]); /* close output side */ 672105197Ssam (void) close(fi); 673105197Ssam if (prchild < 0) { 674105197Ssam prchild = 0; 675105197Ssam (void) close(p[0]); 676105197Ssam return(ERROR); 677105197Ssam } 678105197Ssam fi = p[0]; /* use pipe for input */ 679105197Ssam case 'o': /* print postscript file */ 680105197Ssam /* 681105197Ssam * For now, treat this as a plain-text file, and assume 682105197Ssam * the standard LPF_INPUT filter will recognize that it 683105197Ssam * is postscript and know what to do with it. These 684105197Ssam * 'o'-file requests could come from MacOS 10.1 systems. 685105197Ssam */ 686105197Ssam /* FALLTHROUGH */ 687105197Ssam case 'f': /* print plain text file */ 688252028Sae prog = pp->filters[LPF_INPUT]; 689105197Ssam av[1] = width; 690105197Ssam av[2] = length; 691105197Ssam av[3] = indent; 692105197Ssam n = 4; 693105197Ssam break; 694105197Ssam case 'l': /* like 'f' but pass control characters */ 695105197Ssam prog = pp->filters[LPF_INPUT]; 696105197Ssam av[1] = "-c"; 697117058Ssam av[2] = width; 698105197Ssam av[3] = length; 699105197Ssam av[4] = indent; 700105197Ssam n = 5; 701105197Ssam break; 702105197Ssam case 'r': /* print a fortran text file */ 703105197Ssam prog = pp->filters[LPF_FORTRAN]; 704105197Ssam av[1] = width; 705105197Ssam av[2] = length; 706105197Ssam n = 3; 707105197Ssam break; 708105197Ssam case 't': /* print troff output */ 709105197Ssam case 'n': /* print ditroff output */ 710105197Ssam case 'd': /* print tex output */ 711220206Sfabient (void) unlink(".railmag"); 712220206Sfabient if ((fo = creat(".railmag", FILMOD)) < 0) { 713105197Ssam syslog(LOG_ERR, "%s: cannot create .railmag", 714105197Ssam pp->printer); 715105197Ssam (void) unlink(".railmag"); 716105197Ssam } else { 717105197Ssam for (n = 0; n < 4; n++) { 718105197Ssam if (fonts[n][0] != '/') 719105197Ssam (void) write(fo, _PATH_VFONT, 720105197Ssam sizeof(_PATH_VFONT) - 1); 721105197Ssam (void) write(fo, fonts[n], strlen(fonts[n])); 722105197Ssam (void) write(fo, "\n", 1); 723105197Ssam } 724105197Ssam (void) close(fo); 725105197Ssam } 726105197Ssam prog = (format == 't') ? pp->filters[LPF_TROFF] 727105197Ssam : ((format == 'n') ? pp->filters[LPF_DITROFF] 728105197Ssam : pp->filters[LPF_DVI]); 729105197Ssam av[1] = pxwidth; 730105197Ssam av[2] = pxlength; 731105197Ssam n = 3; 732105197Ssam break; 733105197Ssam case 'c': /* print cifplot output */ 734105197Ssam prog = pp->filters[LPF_CIFPLOT]; 735105197Ssam av[1] = pxwidth; 736105197Ssam av[2] = pxlength; 737119643Ssam n = 3; 738105197Ssam break; 739105197Ssam case 'g': /* print plot(1G) output */ 740105197Ssam prog = pp->filters[LPF_GRAPH]; 741105197Ssam av[1] = pxwidth; 742120585Ssam av[2] = pxlength; 743105197Ssam n = 3; 744105197Ssam break; 745105197Ssam case 'v': /* print raster output */ 746105197Ssam prog = pp->filters[LPF_RASTER]; 747105197Ssam av[1] = pxwidth; 748105197Ssam av[2] = pxlength; 749220206Sfabient n = 3; 750220206Sfabient break; 751105197Ssam default: 752105197Ssam (void) close(fi); 753120585Ssam syslog(LOG_ERR, "%s: illegal format character '%c'", 754105197Ssam pp->printer, format); 755120585Ssam return(ERROR); 756105197Ssam } 757105197Ssam if (prog == NULL) { 758105197Ssam (void) close(fi); 759105197Ssam syslog(LOG_ERR, 760105197Ssam "%s: no filter found in printcap for format character '%c'", 761105197Ssam pp->printer, format); 762105197Ssam return(ERROR); 763105197Ssam } 764228009Spjd if ((av[0] = strrchr(prog, '/')) != NULL) 765228009Spjd av[0]++; 766105197Ssam else 767252028Sae av[0] = prog; 768120585Ssam av[n++] = "-n"; 769105197Ssam av[n++] = logname; 770105197Ssam av[n++] = "-h"; 771105197Ssam av[n++] = origin_host; 772252028Sae av[n++] = pp->acct_file; 773105197Ssam av[n] = 0; 774105197Ssam fo = pfd; 775105197Ssam if (ofilter > 0) { /* stop output filter */ 776105197Ssam write(ofd, "\031\1", 2); 777105197Ssam while ((pid = 778105197Ssam wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 779252028Sae ; 780120585Ssam if (pid < 0) 781105197Ssam syslog(LOG_WARNING, "%s: after stopping 'of', wait3() returned: %m", 782105197Ssam pp->printer); 783105197Ssam else if (status.w_stopval != WSTOPPED) { 784105197Ssam (void) close(fi); 785105197Ssam syslog(LOG_WARNING, 786105197Ssam "%s: output filter died " 787105197Ssam "(pid=%d retcode=%d termsig=%d)", 788105197Ssam pp->printer, ofilter, status.w_retcode, 789105197Ssam status.w_termsig); 790105197Ssam return(REPRINT); 791105197Ssam } 792105197Ssam stopped++; 793105197Ssam } 794105197Ssamstart: 795105197Ssam if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 796105197Ssam dup2(fi, 0); 797105197Ssam dup2(fo, 1); 798105197Ssam /* setup stderr for the filter (child process) 799105197Ssam * so it goes to our temporary errors file */ 800105197Ssam n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 801120585Ssam if (n >= 0) 802120585Ssam dup2(n, 2); 803105197Ssam closelog(); 804105197Ssam closeallfds(3); 805252028Sae execv(prog, av); 806105197Ssam syslog(LOG_ERR, "cannot execv %s", prog); 807105197Ssam exit(2); 808105197Ssam } 809105197Ssam (void) close(fi); 810105197Ssam if (child < 0) 811105197Ssam status.w_retcode = 100; 812105197Ssam else { 813105197Ssam while ((pid = wait((int *)&status)) > 0 && pid != child) 814105197Ssam ; 815105197Ssam if (pid < 0) { 816105197Ssam status.w_retcode = 100; 817105197Ssam syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 818105197Ssam pp->printer, prog); 819105197Ssam } 820105197Ssam } 821105197Ssam child = 0; 822105197Ssam prchild = 0; 823105197Ssam if (stopped) { /* restart output filter */ 824105197Ssam if (kill(ofilter, SIGCONT) < 0) { 825105197Ssam syslog(LOG_ERR, "cannot restart output filter"); 826105197Ssam exit(1); 827105197Ssam } 828105197Ssam } 829105197Ssam pp->tof = 0; 830105197Ssam 831105197Ssam /* Copy the filter's output to "lf" logfile */ 832105197Ssam if ((fp = fopen(tempstderr, "r"))) { 833105197Ssam while (fgets(buf, sizeof(buf), fp)) 834105197Ssam fputs(buf, stderr); 835105197Ssam fclose(fp); 836252028Sae } 837105197Ssam 838105197Ssam if (!WIFEXITED(status)) { 839105197Ssam syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 840105197Ssam pp->printer, format, status.w_termsig); 841105197Ssam return(ERROR); 842105197Ssam } 843105197Ssam switch (status.w_retcode) { 844105197Ssam case 0: 845105197Ssam pp->tof = 1; 846105197Ssam return(OK); 847120585Ssam case 1: 848105197Ssam return(REPRINT); 849105197Ssam case 2: 850252028Sae return(ERROR); 851105197Ssam default: 852105197Ssam syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 853105197Ssam pp->printer, format, status.w_retcode); 854221129Sbz return(FILTERERR); 855221129Sbz } 856221129Sbz} 857221129Sbz 858221129Sbz/* 859221129Sbz * Send the daemon control file (cf) and any data files. 860221129Sbz * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 861221129Sbz * 0 if all is well. 862221129Sbz */ 863221129Sbzstatic int 864221129Sbzsendit(struct printer *pp, char *file) 865221129Sbz{ 866221129Sbz register int i, err = OK; 867221129Sbz char *cp, last[BUFSIZ]; 868221129Sbz 869105197Ssam /* 870105197Ssam * open control file 871105197Ssam */ 872105197Ssam if ((cfp = fopen(file, "r")) == NULL) 873105197Ssam return(OK); 874105197Ssam 875105197Ssam /* initialize job-specific count of datafiles processed */ 876105197Ssam job_dfcnt = 0; 877105197Ssam 878105197Ssam /* 879105197Ssam * read the control file for work to do 880105197Ssam * 881105197Ssam * file format -- first character in the line is a command 882105197Ssam * rest of the line is the argument. 883105197Ssam * commands of interest are: 884105197Ssam * 885105197Ssam * a-z -- "file name" name of file to print 886105197Ssam * U -- "unlink" name of file to remove 887105197Ssam * (after we print it. (Pass 2 only)). 888105197Ssam */ 889105197Ssam 890105197Ssam /* 891105197Ssam * pass 1 892105197Ssam */ 893105197Ssam while (getline(cfp)) { 894105197Ssam again: 895105197Ssam if (line[0] == 'S') { 896105197Ssam cp = line+1; 897105197Ssam i = 0; 898105197Ssam while (*cp >= '0' && *cp <= '9') 899105197Ssam i = i * 10 + (*cp++ - '0'); 900105197Ssam fdev = i; 901105197Ssam cp++; 902105197Ssam i = 0; 903105197Ssam while (*cp >= '0' && *cp <= '9') 904105197Ssam i = i * 10 + (*cp++ - '0'); 905105197Ssam fino = i; 906105197Ssam } else if (line[0] == 'H') { 907120585Ssam strlcpy(origin_host, line + 1, sizeof(origin_host)); 908105197Ssam if (class[0] == '\0') { 909120585Ssam strlcpy(class, line + 1, sizeof(class)); 910105197Ssam } 911252028Sae } else if (line[0] == 'P') { 912105197Ssam strlcpy(logname, line + 1, sizeof(logname)); 913105197Ssam if (pp->restricted) { /* restricted */ 914105197Ssam if (getpwnam(logname) == NULL) { 915105197Ssam sendmail(pp, line+1, NOACCT); 916105197Ssam err = ERROR; 917105197Ssam break; 918105197Ssam } 919105197Ssam } 920105197Ssam } else if (line[0] == 'I') { 921105197Ssam strlcpy(indent+2, line + 1, sizeof(indent) - 2); 922105197Ssam } else if (line[0] >= 'a' && line[0] <= 'z') { 923105197Ssam strcpy(last, line); 924105197Ssam while ((i = getline(cfp)) != 0) 925105197Ssam if (strcmp(last, line)) 926105197Ssam break; 927105197Ssam switch (sendfile(pp, '\3', last+1, *last)) { 928105197Ssam case OK: 929120585Ssam if (i) 930120585Ssam goto again; 931105197Ssam break; 932105197Ssam case REPRINT: 933105197Ssam (void) fclose(cfp); 934252028Sae return(REPRINT); 935105197Ssam case ACCESS: 936105197Ssam sendmail(pp, logname, ACCESS); 937105197Ssam case ERROR: 938105197Ssam err = ERROR; 939105197Ssam } 940120585Ssam break; 941120585Ssam } 942105197Ssam } 943105197Ssam if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 944105197Ssam (void) fclose(cfp); 945252028Sae return(REPRINT); 946105197Ssam } 947105197Ssam /* 948105197Ssam * pass 2 949105197Ssam */ 950105197Ssam fseek(cfp, 0L, 0); 951252028Sae while (getline(cfp)) 952105197Ssam if (line[0] == 'U' && !strchr(line+1, '/')) 953156756Ssam (void) unlink(line+1); 954105197Ssam /* 955120585Ssam * clean-up in case another control file exists 956105197Ssam */ 957105197Ssam (void) fclose(cfp); 958252028Sae (void) unlink(file); 959105197Ssam return(err); 960105197Ssam} 961105197Ssam 962105197Ssam/* 963105197Ssam * Send a data file to the remote machine and spool it. 964105197Ssam * Return positive if we should try resending. 965105197Ssam */ 966120585Ssamstatic int 967120585Ssamsendfile(struct printer *pp, int type, char *file, char format) 968105197Ssam{ 969105197Ssam register int f, i, amt; 970105197Ssam struct stat stb; 971252028Sae FILE *fp; 972105197Ssam char buf[BUFSIZ]; 973105197Ssam int closedpr, resp, sizerr, statrc; 974105197Ssam 975105197Ssam statrc = lstat(file, &stb); 976105197Ssam if (statrc < 0) { 977105197Ssam syslog(LOG_ERR, "%s: error from lstat(%s): %m", 978105197Ssam pp->printer, file); 979105197Ssam return(ERROR); 980105197Ssam } 981105197Ssam f = open(file, O_RDONLY); 982105197Ssam if (f < 0) { 983105197Ssam syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 984105197Ssam pp->printer, file); 985105197Ssam return(ERROR); 986105197Ssam } 987105197Ssam /* 988105197Ssam * Check to see if data file is a symbolic link. If so, it should 989105197Ssam * still point to the same file or someone is trying to print something 990105197Ssam * he shouldn't. 991105197Ssam */ 992105197Ssam if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 993105197Ssam (stb.st_dev != fdev || stb.st_ino != fino)) 994105197Ssam return(ACCESS); 995120585Ssam 996120585Ssam job_dfcnt++; /* increment datafile counter for this job */ 997105197Ssam 998105197Ssam /* everything seems OK, start it up */ 999252028Sae sizerr = 0; 1000105197Ssam closedpr = 0; 1001105197Ssam if (type == '\3') { 1002105197Ssam if (pp->filters[LPF_INPUT]) { 1003157634Spjd /* 1004157613Spjd * We're sending something with an ifilter. We have to 1005181803Sbz * run the ifilter and store the output as a temporary 1006157634Spjd * spool file (tfile...), because the protocol requires 1007157613Spjd * us to send the file size before we start sending any 1008105197Ssam * of the data. 1009105197Ssam */ 1010105197Ssam char *av[15]; 1011105197Ssam int n; 1012105197Ssam int ifilter; 1013105197Ssam union wait status; /* XXX */ 1014120585Ssam 1015120585Ssam strcpy(tfile,TFILENAME); 1016252028Sae if ((tfd = mkstemp(tfile)) == -1) { 1017105197Ssam syslog(LOG_ERR, "mkstemp: %m"); 1018105197Ssam return(ERROR); 1019105197Ssam } 1020105197Ssam if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 1021105197Ssam av[0] = pp->filters[LPF_INPUT]; 1022105197Ssam else 1023105197Ssam av[0]++; 1024105197Ssam if (format == 'l') 1025105197Ssam av[n=1] = "-c"; 1026105197Ssam else 1027105197Ssam n = 0; 1028105197Ssam av[++n] = width; 1029157123Sgnn av[++n] = length; 1030105197Ssam av[++n] = indent; 1031105197Ssam av[++n] = "-n"; 1032105197Ssam av[++n] = logname; 1033105197Ssam av[++n] = "-h"; 1034105197Ssam av[++n] = origin_host; 1035105197Ssam av[++n] = pp->acct_file; 1036105197Ssam av[++n] = 0; 1037120585Ssam if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 1038252028Sae dup2(f, 0); 1039105197Ssam dup2(tfd, 1); 1040105197Ssam /* setup stderr for the filter (child process) 1041105197Ssam * so it goes to our temporary errors file */ 1042105197Ssam n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1043105197Ssam if (n >= 0) 1044105197Ssam dup2(n, 2); 1045105197Ssam closelog(); 1046105197Ssam closeallfds(3); 1047105197Ssam execv(pp->filters[LPF_INPUT], av); 1048105197Ssam syslog(LOG_ERR, "cannot execv %s", 1049105197Ssam pp->filters[LPF_INPUT]); 1050105197Ssam exit(2); 1051105197Ssam } 1052105197Ssam (void) close(f); 1053105197Ssam if (ifilter < 0) 1054105197Ssam status.w_retcode = 100; 1055105197Ssam else { 1056105197Ssam while ((pid = wait((int *)&status)) > 0 && 1057105197Ssam pid != ifilter) 1058105197Ssam ; 1059105197Ssam if (pid < 0) { 1060105197Ssam status.w_retcode = 100; 1061105197Ssam syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 1062105197Ssam pp->printer, pp->filters[LPF_INPUT]); 1063105197Ssam } 1064105197Ssam } 1065105197Ssam /* Copy the filter's output to "lf" logfile */ 1066105197Ssam if ((fp = fopen(tempstderr, "r"))) { 1067105197Ssam while (fgets(buf, sizeof(buf), fp)) 1068105197Ssam fputs(buf, stderr); 1069105197Ssam fclose(fp); 1070105197Ssam } 1071105197Ssam /* process the return-code from the filter */ 1072105197Ssam switch (status.w_retcode) { 1073105197Ssam case 0: 1074105197Ssam break; 1075105197Ssam case 1: 1076105197Ssam unlink(tfile); 1077105197Ssam return(REPRINT); 1078105197Ssam case 2: 1079105197Ssam unlink(tfile); 1080105197Ssam return(ERROR); 1081105197Ssam default: 1082105197Ssam syslog(LOG_WARNING, "%s: filter '%c' exited" 1083105197Ssam " (retcode=%d)", 1084105197Ssam pp->printer, format, status.w_retcode); 1085105197Ssam unlink(tfile); 1086105197Ssam return(FILTERERR); 1087105197Ssam } 1088105197Ssam statrc = fstat(tfd, &stb); /* to find size of tfile */ 1089105197Ssam if (statrc < 0) { 1090105197Ssam syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m", 1091105197Ssam pp->printer, tfile); 1092105197Ssam return(ERROR); 1093105197Ssam } 1094117058Ssam f = tfd; 1095105197Ssam lseek(f,0,SEEK_SET); 1096105197Ssam } else if (ofilter) { 1097105197Ssam /* 1098105197Ssam * We're sending something with an ofilter, we have to 1099105197Ssam * store the output as a temporary file (tfile)... the 1100105197Ssam * protocol requires us to send the file size 1101105197Ssam */ 1102220206Sfabient int i; 1103220206Sfabient for (i = 0; i < stb.st_size; i += BUFSIZ) { 1104105197Ssam amt = BUFSIZ; 1105105197Ssam if (i + amt > stb.st_size) 1106105197Ssam amt = stb.st_size - i; 1107105197Ssam if (sizerr == 0 && read(f, buf, amt) != amt) { 1108105197Ssam sizerr = 1; 1109105197Ssam break; 1110105197Ssam } 1111105197Ssam if (write(ofd, buf, amt) != amt) { 1112105197Ssam (void) close(f); 1113105197Ssam return(REPRINT); 1114105197Ssam } 1115105197Ssam } 1116105197Ssam close(ofd); 1117105197Ssam close(f); 1118105197Ssam while ((i = wait(NULL)) > 0 && i != ofilter) 1119105197Ssam ; 1120105197Ssam if (i < 0) 1121105197Ssam syslog(LOG_WARNING, "%s: after closing 'of', wait() returned: %m", 1122105197Ssam pp->printer); 1123105197Ssam ofilter = 0; 1124105197Ssam statrc = fstat(tfd, &stb); /* to find size of tfile */ 1125105197Ssam if (statrc < 0) { 1126105197Ssam syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m", 1127105197Ssam pp->printer, tfile); 1128105197Ssam openpr(pp); 1129105197Ssam return(ERROR); 1130105197Ssam } 1131120585Ssam f = tfd; 1132105197Ssam lseek(f,0,SEEK_SET); 1133105197Ssam closedpr = 1; 1134105197Ssam } 1135105197Ssam } 1136105197Ssam 1137105197Ssam (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1138120585Ssam amt = strlen(buf); 1139220206Sfabient for (i = 0; ; i++) { 1140220206Sfabient if (write(pfd, buf, amt) != amt || 1141220206Sfabient (resp = response(pp)) < 0 || resp == '\1') { 1142252028Sae (void) close(f); 1143120585Ssam if (tfd != -1 && type == '\3') { 1144105197Ssam tfd = -1; 1145105197Ssam unlink(tfile); 1146105197Ssam if (closedpr) 1147105197Ssam openpr(pp); 1148105197Ssam } 1149105197Ssam return(REPRINT); 1150105197Ssam } else if (resp == '\0') 1151105197Ssam break; 1152105197Ssam if (i == 0) 1153105197Ssam pstatus(pp, 1154120585Ssam "no space on remote; waiting for queue to drain"); 1155228009Spjd if (i == 10) 1156105197Ssam syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1157105197Ssam pp->printer, pp->remote_host); 1158252028Sae sleep(5 * 60); 1159120585Ssam } 1160105197Ssam if (i) 1161105197Ssam pstatus(pp, "sending to %s", pp->remote_host); 1162105197Ssam if (type == '\3') 1163105197Ssam trstat_init(pp, file, job_dfcnt); 1164105197Ssam for (i = 0; i < stb.st_size; i += BUFSIZ) { 1165105197Ssam amt = BUFSIZ; 1166252028Sae if (i + amt > stb.st_size) 1167120585Ssam amt = stb.st_size - i; 1168105197Ssam if (sizerr == 0 && read(f, buf, amt) != amt) 1169105197Ssam sizerr = 1; 1170105197Ssam if (write(pfd, buf, amt) != amt) { 1171252028Sae (void) close(f); 1172105197Ssam if (tfd != -1 && type == '\3') { 1173105197Ssam tfd = -1; 1174105197Ssam unlink(tfile); 1175105197Ssam if (closedpr) 1176105197Ssam openpr(pp); 1177105197Ssam } 1178105197Ssam return(REPRINT); 1179105197Ssam } 1180105197Ssam } 1181105197Ssam 1182105197Ssam (void) close(f); 1183157634Spjd if (tfd != -1 && type == '\3') { 1184157613Spjd tfd = -1; 1185181803Sbz unlink(tfile); 1186157613Spjd } 1187157613Spjd if (sizerr) { 1188157613Spjd syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1189157613Spjd /* tell recvjob to ignore this file */ 1190157613Spjd (void) write(pfd, "\1", 1); 1191157613Spjd if (closedpr) 1192157613Spjd openpr(pp); 1193157613Spjd return(ERROR); 1194157613Spjd } 1195157634Spjd if (write(pfd, "", 1) != 1 || response(pp)) { 1196157613Spjd if (closedpr) 1197105197Ssam openpr(pp); 1198228010Spjd return(REPRINT); 1199105197Ssam } 1200120585Ssam if (closedpr) 1201228010Spjd openpr(pp); 1202105197Ssam if (type == '\3') 1203105197Ssam trstat_write(pp, TR_SENDING, stb.st_size, logname, 1204105197Ssam pp->remote_host, origin_host); 1205120585Ssam return(OK); 1206105197Ssam} 1207105197Ssam 1208105197Ssam/* 1209105197Ssam * Check to make sure there have been no errors and that both programs 1210105197Ssam * are in sync with eachother. 1211105197Ssam * Return non-zero if the connection was lost. 1212105197Ssam */ 1213105197Ssamstatic char 1214105197Ssamresponse(const struct printer *pp) 1215105197Ssam{ 1216105197Ssam char resp; 1217105197Ssam 1218105197Ssam if (read(pfd, &resp, 1) != 1) { 1219105197Ssam syslog(LOG_INFO, "%s: lost connection", pp->printer); 1220105197Ssam return(-1); 1221185088Szec } 1222190787Szec return(resp); 1223190787Szec} 1224190787Szec 1225105197Ssam/* 1226 * Banner printing stuff 1227 */ 1228static void 1229banner(struct printer *pp, char *name1, char *name2) 1230{ 1231 time_t tvec; 1232 1233 time(&tvec); 1234 if (!pp->no_formfeed && !pp->tof) 1235 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1236 if (pp->short_banner) { /* short banner only */ 1237 if (class[0]) { 1238 (void) write(ofd, class, strlen(class)); 1239 (void) write(ofd, ":", 1); 1240 } 1241 (void) write(ofd, name1, strlen(name1)); 1242 (void) write(ofd, " Job: ", 7); 1243 (void) write(ofd, name2, strlen(name2)); 1244 (void) write(ofd, " Date: ", 8); 1245 (void) write(ofd, ctime(&tvec), 24); 1246 (void) write(ofd, "\n", 1); 1247 } else { /* normal banner */ 1248 (void) write(ofd, "\n\n\n", 3); 1249 scan_out(pp, ofd, name1, '\0'); 1250 (void) write(ofd, "\n\n", 2); 1251 scan_out(pp, ofd, name2, '\0'); 1252 if (class[0]) { 1253 (void) write(ofd,"\n\n\n",3); 1254 scan_out(pp, ofd, class, '\0'); 1255 } 1256 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1257 (void) write(ofd, name2, strlen(name2)); 1258 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1259 (void) write(ofd, ctime(&tvec), 24); 1260 (void) write(ofd, "\n", 1); 1261 } 1262 if (!pp->no_formfeed) 1263 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1264 pp->tof = 1; 1265} 1266 1267static char * 1268scnline(int key, char *p, int c) 1269{ 1270 register int scnwidth; 1271 1272 for (scnwidth = WIDTH; --scnwidth;) { 1273 key <<= 1; 1274 *p++ = key & 0200 ? c : BACKGND; 1275 } 1276 return (p); 1277} 1278 1279#define TRC(q) (((q)-' ')&0177) 1280 1281static void 1282scan_out(struct printer *pp, int scfd, char *scsp, int dlm) 1283{ 1284 register char *strp; 1285 register int nchrs, j; 1286 char outbuf[LINELEN+1], *sp, c, cc; 1287 int d, scnhgt; 1288 1289 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1290 strp = &outbuf[0]; 1291 sp = scsp; 1292 for (nchrs = 0; ; ) { 1293 d = dropit(c = TRC(cc = *sp++)); 1294 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1295 for (j = WIDTH; --j;) 1296 *strp++ = BACKGND; 1297 else 1298 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1299 if (*sp == dlm || *sp == '\0' || 1300 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1301 break; 1302 *strp++ = BACKGND; 1303 *strp++ = BACKGND; 1304 } 1305 while (*--strp == BACKGND && strp >= outbuf) 1306 ; 1307 strp++; 1308 *strp++ = '\n'; 1309 (void) write(scfd, outbuf, strp-outbuf); 1310 } 1311} 1312 1313static int 1314dropit(int c) 1315{ 1316 switch(c) { 1317 1318 case TRC('_'): 1319 case TRC(';'): 1320 case TRC(','): 1321 case TRC('g'): 1322 case TRC('j'): 1323 case TRC('p'): 1324 case TRC('q'): 1325 case TRC('y'): 1326 return (DROP); 1327 1328 default: 1329 return (0); 1330 } 1331} 1332 1333/* 1334 * sendmail --- 1335 * tell people about job completion 1336 */ 1337static void 1338sendmail(struct printer *pp, char *user, int bombed) 1339{ 1340 register int i; 1341 int p[2], s; 1342 register const char *cp; 1343 struct stat stb; 1344 FILE *fp; 1345 1346 pipe(p); 1347 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1348 dup2(p[0], 0); 1349 closelog(); 1350 closeallfds(3); 1351 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1352 cp++; 1353 else 1354 cp = _PATH_SENDMAIL; 1355 execl(_PATH_SENDMAIL, cp, "-t", (char *)0); 1356 _exit(0); 1357 } else if (s > 0) { /* parent */ 1358 dup2(p[1], 1); 1359 printf("To: %s@%s\n", user, origin_host); 1360 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1361 *jobname ? jobname : "<unknown>"); 1362 printf("Reply-To: root@%s\n\n", local_host); 1363 printf("Your printer job "); 1364 if (*jobname) 1365 printf("(%s) ", jobname); 1366 1367 cp = "XXX compiler confusion"; /* XXX shut GCC up */ 1368 switch (bombed) { 1369 case OK: 1370 printf("\ncompleted successfully\n"); 1371 cp = "OK"; 1372 break; 1373 default: 1374 case FATALERR: 1375 printf("\ncould not be printed\n"); 1376 cp = "FATALERR"; 1377 break; 1378 case NOACCT: 1379 printf("\ncould not be printed without an account on %s\n", 1380 local_host); 1381 cp = "NOACCT"; 1382 break; 1383 case FILTERERR: 1384 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1385 || (fp = fopen(tempstderr, "r")) == NULL) { 1386 printf("\nhad some errors and may not have printed\n"); 1387 break; 1388 } 1389 printf("\nhad the following errors and may not have printed:\n"); 1390 while ((i = getc(fp)) != EOF) 1391 putchar(i); 1392 (void) fclose(fp); 1393 cp = "FILTERERR"; 1394 break; 1395 case ACCESS: 1396 printf("\nwas not printed because it was not linked to the original file\n"); 1397 cp = "ACCESS"; 1398 } 1399 fflush(stdout); 1400 (void) close(1); 1401 } else { 1402 syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 1403 return; 1404 } 1405 (void) close(p[0]); 1406 (void) close(p[1]); 1407 wait(NULL); 1408 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1409 user, *jobname ? jobname : "<unknown>", pp->printer, cp); 1410} 1411 1412/* 1413 * dofork - fork with retries on failure 1414 */ 1415static int 1416dofork(const struct printer *pp, int action) 1417{ 1418 int i, fail, forkpid; 1419 struct passwd *pwd; 1420 1421 forkpid = -1; 1422 if (daemon_uname == NULL) { 1423 pwd = getpwuid(pp->daemon_user); 1424 if (pwd == NULL) { 1425 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file", 1426 pp->printer, pp->daemon_user); 1427 goto error_ret; 1428 } 1429 daemon_uname = strdup(pwd->pw_name); 1430 daemon_defgid = pwd->pw_gid; 1431 } 1432 1433 for (i = 0; i < 20; i++) { 1434 forkpid = fork(); 1435 if (forkpid < 0) { 1436 sleep((unsigned)(i*i)); 1437 continue; 1438 } 1439 /* 1440 * Child should run as daemon instead of root 1441 */ 1442 if (forkpid == 0) { 1443 errno = 0; 1444 fail = initgroups(daemon_uname, daemon_defgid); 1445 if (fail) { 1446 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m", 1447 pp->printer, daemon_uname, daemon_defgid); 1448 break; 1449 } 1450 fail = setgid(daemon_defgid); 1451 if (fail) { 1452 syslog(LOG_ERR, "%s: setgid(%u): %m", 1453 pp->printer, daemon_defgid); 1454 break; 1455 } 1456 fail = setuid(pp->daemon_user); 1457 if (fail) { 1458 syslog(LOG_ERR, "%s: setuid(%ld): %m", 1459 pp->printer, pp->daemon_user); 1460 break; 1461 } 1462 } 1463 return forkpid; 1464 } 1465 1466 /* 1467 * An error occurred. If the error is in the child process, then 1468 * this routine MUST always exit(). DORETURN only effects how 1469 * errors should be handled in the parent process. 1470 */ 1471error_ret: 1472 if (forkpid == 0) { 1473 syslog(LOG_ERR, "%s: dofork(): aborting child process...", 1474 pp->printer); 1475 exit(1); 1476 } 1477 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer); 1478 1479 sleep(1); /* throttle errors, as a safety measure */ 1480 switch (action) { 1481 case DORETURN: 1482 return -1; 1483 default: 1484 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1485 /* FALLTHROUGH */ 1486 case DOABORT: 1487 exit(1); 1488 } 1489 /*NOTREACHED*/ 1490} 1491 1492/* 1493 * Kill child processes to abort current job. 1494 */ 1495static void 1496abortpr(int signo __unused) 1497{ 1498 1499 (void) unlink(tempstderr); 1500 kill(0, SIGINT); 1501 if (ofilter > 0) 1502 kill(ofilter, SIGCONT); 1503 while (wait(NULL) > 0) 1504 ; 1505 if (ofilter > 0 && tfd != -1) 1506 unlink(tfile); 1507 exit(0); 1508} 1509 1510static void 1511init(struct printer *pp) 1512{ 1513 char *s; 1514 1515 sprintf(&width[2], "%ld", pp->page_width); 1516 sprintf(&length[2], "%ld", pp->page_length); 1517 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1518 sprintf(&pxlength[2], "%ld", pp->page_plength); 1519 if ((s = checkremote(pp)) != 0) { 1520 syslog(LOG_WARNING, "%s", s); 1521 free(s); 1522 } 1523} 1524 1525void 1526startprinting(const char *printer) 1527{ 1528 struct printer myprinter, *pp = &myprinter; 1529 int status; 1530 1531 init_printer(pp); 1532 status = getprintcap(printer, pp); 1533 switch(status) { 1534 case PCAPERR_OSERR: 1535 syslog(LOG_ERR, "can't open printer description file: %m"); 1536 exit(1); 1537 case PCAPERR_NOTFOUND: 1538 syslog(LOG_ERR, "unknown printer: %s", printer); 1539 exit(1); 1540 case PCAPERR_TCLOOP: 1541 fatal(pp, "potential reference loop detected in printcap file"); 1542 default: 1543 break; 1544 } 1545 printjob(pp); 1546} 1547 1548/* 1549 * Acquire line printer or remote connection. 1550 */ 1551static void 1552openpr(const struct printer *pp) 1553{ 1554 int p[2]; 1555 char *cp; 1556 1557 if (pp->remote) { 1558 openrem(pp); 1559 } else if (*pp->lp) { 1560 if ((cp = strchr(pp->lp, '@')) != NULL) 1561 opennet(pp); 1562 else 1563 opentty(pp); 1564 } else { 1565 syslog(LOG_ERR, "%s: no line printer device or host name", 1566 pp->printer); 1567 exit(1); 1568 } 1569 1570 /* 1571 * Start up an output filter, if needed. 1572 */ 1573 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1574 pipe(p); 1575 if (pp->remote) { 1576 strcpy(tfile, TFILENAME); 1577 tfd = mkstemp(tfile); 1578 } 1579 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1580 dup2(p[0], 0); /* pipe is std in */ 1581 /* tfile/printer is stdout */ 1582 dup2(pp->remote ? tfd : pfd, 1); 1583 closelog(); 1584 closeallfds(3); 1585 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1586 cp = pp->filters[LPF_OUTPUT]; 1587 else 1588 cp++; 1589 execl(pp->filters[LPF_OUTPUT], cp, width, length, 1590 (char *)0); 1591 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1592 pp->filters[LPF_OUTPUT]); 1593 exit(1); 1594 } 1595 (void) close(p[0]); /* close input side */ 1596 ofd = p[1]; /* use pipe for output */ 1597 } else { 1598 ofd = pfd; 1599 ofilter = 0; 1600 } 1601} 1602 1603/* 1604 * Printer connected directly to the network 1605 * or to a terminal server on the net 1606 */ 1607static void 1608opennet(const struct printer *pp) 1609{ 1610 register int i; 1611 int resp; 1612 u_long port; 1613 char *ep; 1614 void (*savealrm)(int); 1615 1616 port = strtoul(pp->lp, &ep, 0); 1617 if (*ep != '@' || port > 65535) { 1618 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1619 pp->lp); 1620 exit(1); 1621 } 1622 ep++; 1623 1624 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1625 resp = -1; 1626 savealrm = signal(SIGALRM, alarmhandler); 1627 alarm(pp->conn_timeout); 1628 pfd = getport(pp, ep, port); 1629 alarm(0); 1630 (void)signal(SIGALRM, savealrm); 1631 if (pfd < 0 && errno == ECONNREFUSED) 1632 resp = 1; 1633 else if (pfd >= 0) { 1634 /* 1635 * need to delay a bit for rs232 lines 1636 * to stabilize in case printer is 1637 * connected via a terminal server 1638 */ 1639 delay(500); 1640 break; 1641 } 1642 if (i == 1) { 1643 if (resp < 0) 1644 pstatus(pp, "waiting for %s to come up", 1645 pp->lp); 1646 else 1647 pstatus(pp, 1648 "waiting for access to printer on %s", 1649 pp->lp); 1650 } 1651 sleep(i); 1652 } 1653 pstatus(pp, "sending to %s port %lu", ep, port); 1654} 1655 1656/* 1657 * Printer is connected to an RS232 port on this host 1658 */ 1659static void 1660opentty(const struct printer *pp) 1661{ 1662 register int i; 1663 1664 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1665 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1666 if (pfd >= 0) { 1667 delay(500); 1668 break; 1669 } 1670 if (errno == ENOENT) { 1671 syslog(LOG_ERR, "%s: %m", pp->lp); 1672 exit(1); 1673 } 1674 if (i == 1) 1675 pstatus(pp, 1676 "waiting for %s to become ready (offline?)", 1677 pp->printer); 1678 sleep(i); 1679 } 1680 if (isatty(pfd)) 1681 setty(pp); 1682 pstatus(pp, "%s is ready and printing", pp->printer); 1683} 1684 1685/* 1686 * Printer is on a remote host 1687 */ 1688static void 1689openrem(const struct printer *pp) 1690{ 1691 register int i; 1692 int resp; 1693 void (*savealrm)(int); 1694 1695 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1696 resp = -1; 1697 savealrm = signal(SIGALRM, alarmhandler); 1698 alarm(pp->conn_timeout); 1699 pfd = getport(pp, pp->remote_host, 0); 1700 alarm(0); 1701 (void)signal(SIGALRM, savealrm); 1702 if (pfd >= 0) { 1703 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1704 (char *)0) 1705 == 2 + strlen(pp->remote_queue)) 1706 && (resp = response(pp)) == 0) 1707 break; 1708 (void) close(pfd); 1709 } 1710 if (i == 1) { 1711 if (resp < 0) 1712 pstatus(pp, "waiting for %s to come up", 1713 pp->remote_host); 1714 else { 1715 pstatus(pp, 1716 "waiting for queue to be enabled on %s", 1717 pp->remote_host); 1718 i = 256; 1719 } 1720 } 1721 sleep(i); 1722 } 1723 pstatus(pp, "sending to %s", pp->remote_host); 1724} 1725 1726/* 1727 * setup tty lines. 1728 */ 1729static void 1730setty(const struct printer *pp) 1731{ 1732 struct termios ttybuf; 1733 1734 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1735 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1736 exit(1); 1737 } 1738 if (tcgetattr(pfd, &ttybuf) < 0) { 1739 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1740 exit(1); 1741 } 1742 if (pp->baud_rate > 0) 1743 cfsetspeed(&ttybuf, pp->baud_rate); 1744 if (pp->mode_set) { 1745 char *s = strdup(pp->mode_set), *tmp; 1746 1747 while ((tmp = strsep(&s, ",")) != NULL) { 1748 (void) msearch(tmp, &ttybuf); 1749 } 1750 } 1751 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1752 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1753 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1754 } 1755 } 1756} 1757 1758#ifdef __STDC__ 1759#include <stdarg.h> 1760#else 1761#include <varargs.h> 1762#endif 1763 1764static void 1765#ifdef __STDC__ 1766pstatus(const struct printer *pp, const char *msg, ...) 1767#else 1768pstatus(pp, msg, va_alist) 1769 const struct printer *pp; 1770 char *msg; 1771 va_dcl 1772#endif 1773{ 1774 int fd; 1775 char *buf; 1776 va_list ap; 1777#ifdef __STDC__ 1778 va_start(ap, msg); 1779#else 1780 va_start(ap); 1781#endif 1782 1783 umask(0); 1784 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1785 if (fd < 0) { 1786 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1787 exit(1); 1788 } 1789 ftruncate(fd, 0); 1790 vasprintf(&buf, msg, ap); 1791 va_end(ap); 1792 writel(fd, buf, "\n", (char *)0); 1793 close(fd); 1794 free(buf); 1795} 1796 1797void 1798alarmhandler(int signo __unused) 1799{ 1800 /* the signal is ignored */ 1801 /* (the '__unused' is just to avoid a compile-time warning) */ 1802} 1803