printjob.c revision 80230
1181430Sstas/* 2181430Sstas * Copyright (c) 1983, 1993 3181430Sstas * The Regents of the University of California. All rights reserved. 4181430Sstas * 5181430Sstas * 6181430Sstas * Redistribution and use in source and binary forms, with or without 7181430Sstas * modification, are permitted provided that the following conditions 8181430Sstas * are met: 9181430Sstas * 1. Redistributions of source code must retain the above copyright 10181430Sstas * notice, this list of conditions and the following disclaimer. 11181430Sstas * 2. Redistributions in binary form must reproduce the above copyright 12181430Sstas * notice, this list of conditions and the following disclaimer in the 13181430Sstas * documentation and/or other materials provided with the distribution. 14181430Sstas * 3. All advertising materials mentioning features or use of this software 15181430Sstas * must display the following acknowledgement: 16181430Sstas * This product includes software developed by the University of 17181430Sstas * California, Berkeley and its contributors. 18181430Sstas * 4. Neither the name of the University nor the names of its contributors 19181430Sstas * may be used to endorse or promote products derived from this software 20181430Sstas * without specific prior written permission. 21181430Sstas * 22181430Sstas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23181430Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24181430Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25181430Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26181430Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27181430Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28181430Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29181430Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30181430Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31181430Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32181430Sstas * SUCH DAMAGE. 33181430Sstas */ 34181430Sstas 35181430Sstas#ifndef lint 36181430Sstasstatic const char copyright[] = 37181430Sstas"@(#) Copyright (c) 1983, 1993\n\ 38181430Sstas The Regents of the University of California. All rights reserved.\n"; 39181430Sstas#endif /* not lint */ 40181430Sstas 41181430Sstas#ifndef lint 42181430Sstas/* 43181430Sstasstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 44181430Sstas*/ 45181430Sstasstatic const char rcsid[] = 46181430Sstas "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 80230 2001-07-23 23:13:39Z gad $"; 47181430Sstas#endif /* not lint */ 48181430Sstas 49181430Sstas 50181430Sstas/* 51181430Sstas * printjob -- print jobs in the queue. 52181430Sstas * 53181430Sstas * NOTE: the lock file is used to pass information to lpq and lprm. 54181430Sstas * it does not need to be removed because file locks are dynamic. 55181430Sstas */ 56181430Sstas 57181430Sstas#include <sys/param.h> 58181430Sstas#include <sys/wait.h> 59181430Sstas#include <sys/stat.h> 60181430Sstas#include <sys/types.h> 61181430Sstas 62181430Sstas#include <pwd.h> 63181430Sstas#include <unistd.h> 64181430Sstas#include <signal.h> 65181430Sstas#include <syslog.h> 66275960Skib#include <fcntl.h> 67181430Sstas#include <dirent.h> 68181430Sstas#include <errno.h> 69181430Sstas#include <stdio.h> 70267814Skib#include <string.h> 71181430Sstas#include <stdlib.h> 72267814Skib#include <sys/ioctl.h> 73267651Sattilio#include <termios.h> 74181430Sstas#include <time.h> 75181430Sstas#include "lp.h" 76181430Sstas#include "lp.local.h" 77181430Sstas#include "pathnames.h" 78181430Sstas#include "extern.h" 79228436Sfabient 80228436Sfabient#define DORETURN 0 /* dofork should return "can't fork" error */ 81181430Sstas#define DOABORT 1 /* dofork should just die if fork() fails */ 82181430Sstas 83181430Sstas/* 84181430Sstas * Error tokens 85181430Sstas */ 86181430Sstas#define REPRINT -2 87181430Sstas#define ERROR -1 88181430Sstas#define OK 0 89181430Sstas#define FATALERR 1 90181430Sstas#define NOACCT 2 91181430Sstas#define FILTERERR 3 92181430Sstas#define ACCESS 4 93181430Sstas 94181430Sstasstatic dev_t fdev; /* device of file pointed to by symlink */ 95181430Sstasstatic ino_t fino; /* inode of file pointed to by symlink */ 96181430Sstasstatic FILE *cfp; /* control file */ 97181430Sstasstatic int child; /* id of any filters */ 98181430Sstasstatic int job_dfcnt; /* count of datafiles in current user job */ 99181430Sstasstatic int lfd; /* lock file descriptor */ 100181430Sstasstatic int ofd; /* output filter file descriptor */ 101181430Sstasstatic int ofilter; /* id of output filter, if any */ 102181430Sstasstatic int tfd = -1; /* output filter temp file output */ 103181430Sstasstatic int pfd; /* prstatic inter file descriptor */ 104181430Sstasstatic int pid; /* pid of lpd process */ 105181430Sstasstatic int prchild; /* id of pr process */ 106181430Sstasstatic char title[80]; /* ``pr'' title */ 107181430Sstasstatic char locale[80]; /* ``pr'' locale */ 108181430Sstas 109181430Sstas/* these two are set from pp->daemon_user, but only if they are needed */ 110181430Sstasstatic char *daemon_uname; /* set from pwd->pw_name */ 111181430Sstasstatic int daemon_defgid; 112181430Sstas 113181430Sstasstatic char class[32]; /* classification field */ 114181430Sstasstatic char origin_host[MAXHOSTNAMELEN]; /* user's host machine */ 115181430Sstas /* indentation size in static characters */ 116181430Sstasstatic char indent[10] = "-i0"; 117181430Sstasstatic char jobname[100]; /* job or file name */ 118181430Sstasstatic char length[10] = "-l"; /* page length in lines */ 119181430Sstasstatic char logname[32]; /* user's login name */ 120181430Sstasstatic char pxlength[10] = "-y"; /* page length in pixels */ 121181430Sstasstatic char pxwidth[10] = "-x"; /* page width in pixels */ 122181430Sstas/* tempstderr is the filename used to catch stderr from exec-ing filters */ 123181430Sstasstatic char tempstderr[] = "errs.XXXXXXX"; 124181430Sstasstatic char width[10] = "-w"; /* page width in static characters */ 125181430Sstas#define TFILENAME "fltXXXXXX" 126181430Sstasstatic char tfile[] = TFILENAME; /* file name for filter output */ 127181430Sstas 128181430Sstasstatic void abortpr(int _signo); 129300424Sachestatic void alarmhandler(int _signo); 130181430Sstasstatic void banner(struct printer *_pp, char *_name1, char *_name2); 131181430Sstasstatic int dofork(const struct printer *_pp, int _action); 132181430Sstasstatic int dropit(int _c); 133181430Sstasstatic void init(struct printer *_pp); 134181430Sstasstatic void openpr(const struct printer *_pp); 135181430Sstasstatic void opennet(const struct printer *_pp); 136181430Sstasstatic void opentty(const struct printer *_pp); 137181430Sstasstatic void openrem(const struct printer *pp); 138181430Sstasstatic int print(struct printer *_pp, int _format, char *_file); 139181430Sstasstatic int printit(struct printer *_pp, char *_file); 140181430Sstasstatic void pstatus(const struct printer *_pp, const char *_msg, ...) 141181430Sstas __printflike(2, 3); 142181430Sstasstatic char response(const struct printer *_pp); 143181430Sstasstatic void scan_out(struct printer *_pp, int _scfd, char *_scsp, 144181430Sstas int _dlm); 145181430Sstasstatic char *scnline(int _key, char *_p, int _c); 146181430Sstasstatic int sendfile(struct printer *_pp, int _type, char *_file, 147181430Sstas char _format); 148181430Sstasstatic int sendit(struct printer *_pp, char *_file); 149181430Sstasstatic void sendmail(struct printer *_pp, char *_user, int _bombed); 150181430Sstasstatic void setty(const struct printer *_pp); 151183397Sed 152181430Sstasvoid 153181430Sstasprintjob(struct printer *pp) 154181430Sstas{ 155181430Sstas struct stat stb; 156181430Sstas register struct jobqueue *q, **qp; 157181430Sstas struct jobqueue **queue; 158181430Sstas register int i, nitems; 159181430Sstas off_t pidoff; 160181430Sstas int errcnt, jobcount, tempfd; 161181430Sstas 162181430Sstas jobcount = 0; 163181430Sstas init(pp); /* set up capabilities */ 164181430Sstas (void) write(1, "", 1); /* ack that daemon is started */ 165195189Sstas (void) close(2); /* set up log file */ 166195189Sstas if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 167181430Sstas syslog(LOG_ERR, "%s: %m", pp->log_file); 168181430Sstas (void) open(_PATH_DEVNULL, O_WRONLY); 169181430Sstas } 170181430Sstas setgid(getegid()); 171181430Sstas pid = getpid(); /* for use with lprm */ 172181430Sstas setpgrp(0, pid); 173181430Sstas 174267814Skib /* 175267814Skib * At initial lpd startup, printjob may be called with various 176181430Sstas * signal handlers in effect. After that initial startup, any 177181430Sstas * calls to printjob will have a *different* set of signal-handlers 178181430Sstas * in effect. Make sure all handlers are the ones we want. 179181430Sstas */ 180181430Sstas signal(SIGCHLD, SIG_DFL); 181181430Sstas signal(SIGHUP, abortpr); 182181430Sstas signal(SIGINT, abortpr); 183267651Sattilio signal(SIGQUIT, abortpr); 184267814Skib signal(SIGTERM, abortpr); 185267814Skib 186267814Skib /* 187267651Sattilio * uses short form file names 188181430Sstas */ 189181430Sstas if (chdir(pp->spool_dir) < 0) { 190181430Sstas syslog(LOG_ERR, "%s: %m", pp->spool_dir); 191181430Sstas exit(1); 192181430Sstas } 193181430Sstas if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 194181430Sstas exit(0); /* printing disabled */ 195181430Sstas lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 196181430Sstas LOCK_FILE_MODE); 197181430Sstas if (lfd < 0) { 198181430Sstas if (errno == EWOULDBLOCK) /* active daemon present */ 199267814Skib exit(0); 200267673Skib syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 201267673Skib exit(1); 202181430Sstas } 203181430Sstas /* turn off non-blocking mode (was turned on for lock effects only) */ 204181430Sstas if (fcntl(lfd, F_SETFL, 0) < 0) { 205181430Sstas syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 206181430Sstas exit(1); 207181430Sstas } 208181430Sstas ftruncate(lfd, 0); 209181430Sstas /* 210181430Sstas * write process id for others to know 211267651Sattilio */ 212267651Sattilio sprintf(line, "%u\n", pid); 213181430Sstas pidoff = i = strlen(line); 214181430Sstas if (write(lfd, line, i) != i) { 215181430Sstas syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 216267651Sattilio exit(1); 217181430Sstas } 218181430Sstas /* 219181430Sstas * search the spool directory for work and sort by queue order. 220267814Skib */ 221267651Sattilio if ((nitems = getq(pp, &queue)) < 0) { 222267651Sattilio syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 223267673Skib pp->spool_dir); 224267651Sattilio exit(1); 225267673Skib } 226267651Sattilio if (nitems == 0) /* no work to do */ 227267673Skib exit(0); 228267814Skib if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 229267673Skib if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 230267651Sattilio syslog(LOG_ERR, "%s: %s: %m", pp->printer, 231267651Sattilio pp->lock_file); 232181430Sstas } 233181430Sstas 234181430Sstas /* create a file which will be used to hold stderr from filters */ 235181430Sstas if ((tempfd = mkstemp(tempstderr)) == -1) { 236181430Sstas syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 237181430Sstas tempstderr); 238195189Sstas exit(1); 239181430Sstas } 240181430Sstas if ((i = fchmod(tempfd, 0664)) == -1) { 241181430Sstas syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 242181430Sstas tempstderr); 243181430Sstas exit(1); 244181430Sstas } 245181430Sstas /* lpd doesn't need it to be open, it just needs it to exist */ 246181430Sstas close(tempfd); 247181430Sstas 248181430Sstas openpr(pp); /* open printer or remote */ 249181430Sstasagain: 250181430Sstas /* 251181430Sstas * we found something to do now do it -- 252181430Sstas * write the name of the current control file into the lock file 253181430Sstas * so the spool queue program can tell what we're working on 254181430Sstas */ 255195081Sstas for (qp = queue; nitems--; free((char *) q)) { 256195081Sstas q = *qp++; 257195081Sstas if (stat(q->job_cfname, &stb) < 0) 258195189Sstas continue; 259195081Sstas errcnt = 0; 260195189Sstas restart: 261195189Sstas (void) lseek(lfd, pidoff, 0); 262195189Sstas (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 263195189Sstas i = strlen(line); 264195189Sstas if (write(lfd, line, i) != i) 265195189Sstas syslog(LOG_ERR, "%s: %s: %m", pp->printer, 266195189Sstas pp->lock_file); 267195189Sstas if (!pp->remote) 268195189Sstas i = printit(pp, q->job_cfname); 269195189Sstas else 270195189Sstas i = sendit(pp, q->job_cfname); 271195189Sstas /* 272195189Sstas * Check to see if we are supposed to stop printing or 273195189Sstas * if we are to rebuild the queue. 274181430Sstas */ 275181430Sstas if (fstat(lfd, &stb) == 0) { 276181430Sstas /* stop printing before starting next job? */ 277181430Sstas if (stb.st_mode & LFM_PRINT_DIS) 278181430Sstas goto done; 279181430Sstas /* rebuild queue (after lpc topq) */ 280181430Sstas if (stb.st_mode & LFM_RESET_QUE) { 281181430Sstas for (free(q); nitems--; free(q)) 282181430Sstas q = *qp++; 283181430Sstas if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 284181430Sstas < 0) 285181430Sstas syslog(LOG_WARNING, "%s: %s: %m", 286181430Sstas pp->printer, pp->lock_file); 287181430Sstas break; 288181430Sstas } 289181430Sstas } 290181430Sstas if (i == OK) /* all files of this job printed */ 291181430Sstas jobcount++; 292181430Sstas else if (i == REPRINT && ++errcnt < 5) { 293181430Sstas /* try reprinting the job */ 294267814Skib syslog(LOG_INFO, "restarting %s", pp->printer); 295181430Sstas if (ofilter > 0) { 296181430Sstas kill(ofilter, SIGCONT); /* to be sure */ 297181430Sstas (void) close(ofd); 298181430Sstas while ((i = wait(NULL)) > 0 && i != ofilter) 299181430Sstas ; 300181430Sstas if (i < 0) 301228436Sfabient syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m", 302181430Sstas pp->printer, ofilter); 303228436Sfabient ofilter = 0; 304228436Sfabient } 305181430Sstas (void) close(pfd); /* close printer */ 306181430Sstas if (ftruncate(lfd, pidoff) < 0) 307181430Sstas syslog(LOG_WARNING, "%s: %s: %m", 308181430Sstas pp->printer, pp->lock_file); 309181430Sstas openpr(pp); /* try to reopen printer */ 310181430Sstas goto restart; 311181430Sstas } else { 312181430Sstas syslog(LOG_WARNING, "%s: job could not be %s (%s)", 313255439Skib pp->printer, 314181430Sstas pp->remote ? "sent to remote host" : "printed", 315181430Sstas q->job_cfname); 316255439Skib if (i == REPRINT) { 317181430Sstas /* ensure we don't attempt this job again */ 318181430Sstas (void) unlink(q->job_cfname); 319181430Sstas q->job_cfname[0] = 'd'; 320181430Sstas (void) unlink(q->job_cfname); 321181430Sstas if (logname[0]) 322181430Sstas sendmail(pp, logname, FATALERR); 323181430Sstas } 324181430Sstas } 325181430Sstas } 326181430Sstas free(queue); 327181430Sstas /* 328181430Sstas * search the spool directory for more work. 329181430Sstas */ 330255439Skib if ((nitems = getq(pp, &queue)) < 0) { 331255439Skib syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 332255439Skib pp->spool_dir); 333181430Sstas exit(1); 334181430Sstas } 335181430Sstas if (nitems == 0) { /* no more work to do */ 336181430Sstas done: 337181430Sstas if (jobcount > 0) { /* jobs actually printed */ 338181430Sstas if (!pp->no_formfeed && !pp->tof) 339181430Sstas (void) write(ofd, pp->form_feed, 340181430Sstas strlen(pp->form_feed)); 341181430Sstas if (pp->trailer != NULL) /* output trailer */ 342181430Sstas (void) write(ofd, pp->trailer, 343181430Sstas strlen(pp->trailer)); 344181430Sstas } 345252592Srpaulo (void) close(ofd); 346181430Sstas (void) wait(NULL); 347181430Sstas (void) unlink(tempstderr); 348181430Sstas exit(0); 349181430Sstas } 350181430Sstas goto again; 351181430Sstas} 352181430Sstas 353181430Sstaschar fonts[4][50]; /* fonts for troff */ 354181430Sstas 355181430Sstaschar ifonts[4][40] = { 356181430Sstas _PATH_VFONTR, 357181430Sstas _PATH_VFONTI, 358252592Srpaulo _PATH_VFONTB, 359181430Sstas _PATH_VFONTS, 360181430Sstas}; 361181430Sstas 362181430Sstas/* 363181430Sstas * The remaining part is the reading of the control file (cf) 364181430Sstas * and performing the various actions. 365254191Skib */ 366181430Sstasstatic int 367181430Sstasprintit(struct printer *pp, char *file) 368181430Sstas{ 369181430Sstas register int i; 370181430Sstas char *cp; 371181430Sstas int bombed, didignorehdr; 372181430Sstas 373181430Sstas bombed = OK; 374181430Sstas didignorehdr = 0; 375181430Sstas /* 376181430Sstas * open control file; ignore if no longer there. 377181430Sstas */ 378181430Sstas if ((cfp = fopen(file, "r")) == NULL) { 379181430Sstas syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 380181430Sstas return(OK); 381181430Sstas } 382181430Sstas /* 383181430Sstas * Reset troff fonts. 384181430Sstas */ 385181430Sstas for (i = 0; i < 4; i++) 386181430Sstas strcpy(fonts[i], ifonts[i]); 387181430Sstas sprintf(&width[2], "%ld", pp->page_width); 388181430Sstas strcpy(indent+2, "0"); 389181430Sstas 390181430Sstas /* initialize job-specific count of datafiles processed */ 391181430Sstas job_dfcnt = 0; 392181430Sstas 393181430Sstas /* 394181430Sstas * read the control file for work to do 395181430Sstas * 396181430Sstas * file format -- first character in the line is a command 397181430Sstas * rest of the line is the argument. 398181430Sstas * valid commands are: 399181430Sstas * 400181430Sstas * S -- "stat info" for symbolic link protection 401181430Sstas * J -- "job name" on banner page 402181430Sstas * C -- "class name" on banner page 403181430Sstas * L -- "literal" user's name to print on banner 404181430Sstas * T -- "title" for pr 405181430Sstas * H -- "host name" of machine where lpr was done 406181430Sstas * P -- "person" user's login name 407181430Sstas * I -- "indent" amount to indent output 408181430Sstas * R -- laser dpi "resolution" 409195081Sstas * f -- "file name" name of text file to print 410181430Sstas * l -- "file name" text file with control chars 411181430Sstas * p -- "file name" text file to print with pr(1) 412181430Sstas * t -- "file name" troff(1) file to print 413181430Sstas * n -- "file name" ditroff(1) file to print 414181430Sstas * d -- "file name" dvi file to print 415181430Sstas * g -- "file name" plot(1G) file to print 416181430Sstas * v -- "file name" plain raster file to print 417181430Sstas * c -- "file name" cifplot file to print 418181430Sstas * 1 -- "R font file" for troff 419181430Sstas * 2 -- "I font file" for troff 420181430Sstas * 3 -- "B font file" for troff 421181430Sstas * 4 -- "S font file" for troff 422181430Sstas * N -- "name" of file (used by lpq) 423181430Sstas * U -- "unlink" name of file to remove 424228436Sfabient * (after we print it. (Pass 2 only)). 425228436Sfabient * M -- "mail" to user when done printing 426228436Sfabient * Z -- "locale" for pr 427255439Skib * 428228436Sfabient * getline reads a line and expands tabs to blanks 429228436Sfabient */ 430255439Skib 431228436Sfabient /* pass 1 */ 432228436Sfabient 433228436Sfabient while (getline(cfp)) 434228436Sfabient switch (line[0]) { 435228436Sfabient case 'H': 436228436Sfabient strlcpy(origin_host, line + 1, sizeof(origin_host)); 437228436Sfabient if (class[0] == '\0') { 438228436Sfabient strlcpy(class, line+1, sizeof(class)); 439228436Sfabient } 440228436Sfabient continue; 441228436Sfabient 442228436Sfabient case 'P': 443228436Sfabient strlcpy(logname, line + 1, sizeof(logname)); 444228436Sfabient if (pp->restricted) { /* restricted */ 445228436Sfabient if (getpwnam(logname) == NULL) { 446255439Skib bombed = NOACCT; 447228436Sfabient sendmail(pp, line+1, bombed); 448228436Sfabient goto pass2; 449228436Sfabient } 450228436Sfabient } 451228436Sfabient continue; 452228436Sfabient 453228436Sfabient case 'S': 454228436Sfabient cp = line+1; 455228436Sfabient i = 0; 456228436Sfabient while (*cp >= '0' && *cp <= '9') 457252592Srpaulo i = i * 10 + (*cp++ - '0'); 458228436Sfabient fdev = i; 459228436Sfabient cp++; 460228436Sfabient i = 0; 461228436Sfabient while (*cp >= '0' && *cp <= '9') 462228436Sfabient i = i * 10 + (*cp++ - '0'); 463228436Sfabient fino = i; 464228436Sfabient continue; 465228436Sfabient 466228436Sfabient case 'J': 467228436Sfabient if (line[1] != '\0') { 468228436Sfabient strlcpy(jobname, line + 1, sizeof(jobname)); 469228436Sfabient } else 470228436Sfabient strcpy(jobname, " "); 471228436Sfabient continue; 472228436Sfabient 473228436Sfabient case 'C': 474228436Sfabient if (line[1] != '\0') 475228436Sfabient strlcpy(class, line + 1, sizeof(class)); 476228436Sfabient else if (class[0] == '\0') { 477228436Sfabient /* XXX - why call gethostname instead of 478228436Sfabient * just strlcpy'ing local_host? */ 479228436Sfabient gethostname(class, sizeof(class)); 480228436Sfabient class[sizeof(class) - 1] = '\0'; 481228436Sfabient } 482228436Sfabient continue; 483228436Sfabient 484228436Sfabient case 'T': /* header title for pr */ 485228436Sfabient strlcpy(title, line + 1, sizeof(title)); 486228436Sfabient continue; 487228436Sfabient 488228436Sfabient case 'L': /* identification line */ 489228436Sfabient if (!pp->no_header && !pp->header_last) 490228436Sfabient banner(pp, line+1, jobname); 491228436Sfabient continue; 492228436Sfabient 493254191Skib case '1': /* troff fonts */ 494228436Sfabient case '2': 495228436Sfabient case '3': 496228436Sfabient case '4': 497181430Sstas if (line[1] != '\0') { 498181430Sstas strlcpy(fonts[line[0]-'1'], line + 1, 499181430Sstas (size_t)50); 500181430Sstas } 501181430Sstas continue; 502181430Sstas 503183397Sed case 'W': /* page width */ 504181430Sstas strlcpy(width+2, line + 1, sizeof(width) - 2); 505181430Sstas continue; 506181430Sstas 507181430Sstas case 'I': /* indent amount */ 508181430Sstas strlcpy(indent+2, line + 1, sizeof(indent) - 2); 509181430Sstas continue; 510181430Sstas 511181430Sstas case 'Z': /* locale for pr */ 512181430Sstas strlcpy(locale, line + 1, sizeof(locale)); 513181430Sstas locale[sizeof(locale) - 1] = '\0'; 514181430Sstas continue; 515181430Sstas 516181430Sstas default: /* some file to print */ 517181430Sstas /* only lowercase cmd-codes include a file-to-print */ 518181430Sstas if ((line[0] < 'a') || (line[0] > 'z')) { 519181430Sstas /* ignore any other lines */ 520181430Sstas if (lflag <= 1) 521181430Sstas continue; 522181430Sstas if (!didignorehdr) { 523181430Sstas syslog(LOG_INFO, "%s: in %s :", 524181430Sstas pp->printer, file); 525181430Sstas didignorehdr = 1; 526181430Sstas } 527181430Sstas syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 528263080Skib pp->printer, line[0], &line[1]); 529263080Skib continue; 530181430Sstas } 531181430Sstas i = print(pp, line[0], line+1); 532181430Sstas switch (i) { 533181430Sstas case ERROR: 534181430Sstas if (bombed == OK) 535181430Sstas bombed = FATALERR; 536181430Sstas break; 537181430Sstas case REPRINT: 538181430Sstas (void) fclose(cfp); 539181430Sstas return(REPRINT); 540181430Sstas case FILTERERR: 541181430Sstas case ACCESS: 542181430Sstas bombed = i; 543181430Sstas sendmail(pp, logname, bombed); 544181430Sstas } 545181430Sstas title[0] = '\0'; 546181430Sstas continue; 547181430Sstas 548181430Sstas case 'N': 549181430Sstas case 'U': 550181430Sstas case 'M': 551181430Sstas case 'R': 552 continue; 553 } 554 555 /* pass 2 */ 556 557pass2: 558 fseek(cfp, 0L, 0); 559 while (getline(cfp)) 560 switch (line[0]) { 561 case 'L': /* identification line */ 562 if (!pp->no_header && pp->header_last) 563 banner(pp, line+1, jobname); 564 continue; 565 566 case 'M': 567 if (bombed < NOACCT) /* already sent if >= NOACCT */ 568 sendmail(pp, line+1, bombed); 569 continue; 570 571 case 'U': 572 if (strchr(line+1, '/')) 573 continue; 574 (void) unlink(line+1); 575 } 576 /* 577 * clean-up in case another control file exists 578 */ 579 (void) fclose(cfp); 580 (void) unlink(file); 581 return(bombed == OK ? OK : ERROR); 582} 583 584/* 585 * Print a file. 586 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 587 * Return -1 if a non-recoverable error occured, 588 * 2 if the filter detected some errors (but printed the job anyway), 589 * 1 if we should try to reprint this job and 590 * 0 if all is well. 591 * Note: all filters take stdin as the file, stdout as the printer, 592 * stderr as the log file, and must not ignore SIGINT. 593 */ 594static int 595print(struct printer *pp, int format, char *file) 596{ 597 register int n, i; 598 register char *prog; 599 int fi, fo; 600 FILE *fp; 601 char *av[15], buf[BUFSIZ]; 602 int pid, p[2], stopped; 603 union wait status; 604 struct stat stb; 605 606 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 607 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 608 pp->printer, file, format); 609 return(ERROR); 610 } 611 /* 612 * Check to see if data file is a symbolic link. If so, it should 613 * still point to the same file or someone is trying to print 614 * something he shouldn't. 615 */ 616 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 617 (stb.st_dev != fdev || stb.st_ino != fino)) 618 return(ACCESS); 619 620 job_dfcnt++; /* increment datafile counter for this job */ 621 stopped = 0; /* output filter is not stopped */ 622 623 /* everything seems OK, start it up */ 624 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 625 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 626 pp->tof = 1; 627 } 628 if (pp->filters[LPF_INPUT] == NULL 629 && (format == 'f' || format == 'l')) { 630 pp->tof = 0; 631 while ((n = read(fi, buf, BUFSIZ)) > 0) 632 if (write(ofd, buf, n) != n) { 633 (void) close(fi); 634 return(REPRINT); 635 } 636 (void) close(fi); 637 return(OK); 638 } 639 switch (format) { 640 case 'p': /* print file using 'pr' */ 641 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 642 prog = _PATH_PR; 643 i = 0; 644 av[i++] = "pr"; 645 av[i++] = width; 646 av[i++] = length; 647 av[i++] = "-h"; 648 av[i++] = *title ? title : " "; 649 av[i++] = "-L"; 650 av[i++] = *locale ? locale : "C"; 651 av[i++] = "-F"; 652 av[i] = 0; 653 fo = ofd; 654 goto start; 655 } 656 pipe(p); 657 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 658 dup2(fi, 0); /* file is stdin */ 659 dup2(p[1], 1); /* pipe is stdout */ 660 closelog(); 661 closeallfds(3); 662 execl(_PATH_PR, "pr", width, length, 663 "-h", *title ? title : " ", 664 "-L", *locale ? locale : "C", 665 "-F", (char *)0); 666 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 667 exit(2); 668 } 669 (void) close(p[1]); /* close output side */ 670 (void) close(fi); 671 if (prchild < 0) { 672 prchild = 0; 673 (void) close(p[0]); 674 return(ERROR); 675 } 676 fi = p[0]; /* use pipe for input */ 677 case 'f': /* print plain text file */ 678 prog = pp->filters[LPF_INPUT]; 679 av[1] = width; 680 av[2] = length; 681 av[3] = indent; 682 n = 4; 683 break; 684 case 'l': /* like 'f' but pass control characters */ 685 prog = pp->filters[LPF_INPUT]; 686 av[1] = "-c"; 687 av[2] = width; 688 av[3] = length; 689 av[4] = indent; 690 n = 5; 691 break; 692 case 'r': /* print a fortran text file */ 693 prog = pp->filters[LPF_FORTRAN]; 694 av[1] = width; 695 av[2] = length; 696 n = 3; 697 break; 698 case 't': /* print troff output */ 699 case 'n': /* print ditroff output */ 700 case 'd': /* print tex output */ 701 (void) unlink(".railmag"); 702 if ((fo = creat(".railmag", FILMOD)) < 0) { 703 syslog(LOG_ERR, "%s: cannot create .railmag", 704 pp->printer); 705 (void) unlink(".railmag"); 706 } else { 707 for (n = 0; n < 4; n++) { 708 if (fonts[n][0] != '/') 709 (void) write(fo, _PATH_VFONT, 710 sizeof(_PATH_VFONT) - 1); 711 (void) write(fo, fonts[n], strlen(fonts[n])); 712 (void) write(fo, "\n", 1); 713 } 714 (void) close(fo); 715 } 716 prog = (format == 't') ? pp->filters[LPF_TROFF] 717 : ((format == 'n') ? pp->filters[LPF_DITROFF] 718 : pp->filters[LPF_DVI]); 719 av[1] = pxwidth; 720 av[2] = pxlength; 721 n = 3; 722 break; 723 case 'c': /* print cifplot output */ 724 prog = pp->filters[LPF_CIFPLOT]; 725 av[1] = pxwidth; 726 av[2] = pxlength; 727 n = 3; 728 break; 729 case 'g': /* print plot(1G) output */ 730 prog = pp->filters[LPF_GRAPH]; 731 av[1] = pxwidth; 732 av[2] = pxlength; 733 n = 3; 734 break; 735 case 'v': /* print raster output */ 736 prog = pp->filters[LPF_RASTER]; 737 av[1] = pxwidth; 738 av[2] = pxlength; 739 n = 3; 740 break; 741 default: 742 (void) close(fi); 743 syslog(LOG_ERR, "%s: illegal format character '%c'", 744 pp->printer, format); 745 return(ERROR); 746 } 747 if (prog == NULL) { 748 (void) close(fi); 749 syslog(LOG_ERR, 750 "%s: no filter found in printcap for format character '%c'", 751 pp->printer, format); 752 return(ERROR); 753 } 754 if ((av[0] = strrchr(prog, '/')) != NULL) 755 av[0]++; 756 else 757 av[0] = prog; 758 av[n++] = "-n"; 759 av[n++] = logname; 760 av[n++] = "-h"; 761 av[n++] = origin_host; 762 av[n++] = pp->acct_file; 763 av[n] = 0; 764 fo = pfd; 765 if (ofilter > 0) { /* stop output filter */ 766 write(ofd, "\031\1", 2); 767 while ((pid = 768 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 769 ; 770 if (pid < 0) 771 syslog(LOG_WARNING, "%s: after stopping 'of', wait3() returned: %m", 772 pp->printer); 773 else if (status.w_stopval != WSTOPPED) { 774 (void) close(fi); 775 syslog(LOG_WARNING, 776 "%s: output filter died " 777 "(pid=%d retcode=%d termsig=%d)", 778 pp->printer, ofilter, status.w_retcode, 779 status.w_termsig); 780 return(REPRINT); 781 } 782 stopped++; 783 } 784start: 785 if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 786 dup2(fi, 0); 787 dup2(fo, 1); 788 /* setup stderr for the filter (child process) 789 * so it goes to our temporary errors file */ 790 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 791 if (n >= 0) 792 dup2(n, 2); 793 closelog(); 794 closeallfds(3); 795 execv(prog, av); 796 syslog(LOG_ERR, "cannot execv %s", prog); 797 exit(2); 798 } 799 (void) close(fi); 800 if (child < 0) 801 status.w_retcode = 100; 802 else { 803 while ((pid = wait((int *)&status)) > 0 && pid != child) 804 ; 805 if (pid < 0) { 806 status.w_retcode = 100; 807 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 808 pp->printer, prog); 809 } 810 } 811 child = 0; 812 prchild = 0; 813 if (stopped) { /* restart output filter */ 814 if (kill(ofilter, SIGCONT) < 0) { 815 syslog(LOG_ERR, "cannot restart output filter"); 816 exit(1); 817 } 818 } 819 pp->tof = 0; 820 821 /* Copy the filter's output to "lf" logfile */ 822 if ((fp = fopen(tempstderr, "r"))) { 823 while (fgets(buf, sizeof(buf), fp)) 824 fputs(buf, stderr); 825 fclose(fp); 826 } 827 828 if (!WIFEXITED(status)) { 829 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 830 pp->printer, format, status.w_termsig); 831 return(ERROR); 832 } 833 switch (status.w_retcode) { 834 case 0: 835 pp->tof = 1; 836 return(OK); 837 case 1: 838 return(REPRINT); 839 case 2: 840 return(ERROR); 841 default: 842 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 843 pp->printer, format, status.w_retcode); 844 return(FILTERERR); 845 } 846} 847 848/* 849 * Send the daemon control file (cf) and any data files. 850 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 851 * 0 if all is well. 852 */ 853static int 854sendit(struct printer *pp, char *file) 855{ 856 register int i, err = OK; 857 char *cp, last[BUFSIZ]; 858 859 /* 860 * open control file 861 */ 862 if ((cfp = fopen(file, "r")) == NULL) 863 return(OK); 864 865 /* initialize job-specific count of datafiles processed */ 866 job_dfcnt = 0; 867 868 /* 869 * read the control file for work to do 870 * 871 * file format -- first character in the line is a command 872 * rest of the line is the argument. 873 * commands of interest are: 874 * 875 * a-z -- "file name" name of file to print 876 * U -- "unlink" name of file to remove 877 * (after we print it. (Pass 2 only)). 878 */ 879 880 /* 881 * pass 1 882 */ 883 while (getline(cfp)) { 884 again: 885 if (line[0] == 'S') { 886 cp = line+1; 887 i = 0; 888 while (*cp >= '0' && *cp <= '9') 889 i = i * 10 + (*cp++ - '0'); 890 fdev = i; 891 cp++; 892 i = 0; 893 while (*cp >= '0' && *cp <= '9') 894 i = i * 10 + (*cp++ - '0'); 895 fino = i; 896 } else if (line[0] == 'H') { 897 strlcpy(origin_host, line + 1, sizeof(origin_host)); 898 if (class[0] == '\0') { 899 strlcpy(class, line + 1, sizeof(class)); 900 } 901 } else if (line[0] == 'P') { 902 strlcpy(logname, line + 1, sizeof(logname)); 903 if (pp->restricted) { /* restricted */ 904 if (getpwnam(logname) == NULL) { 905 sendmail(pp, line+1, NOACCT); 906 err = ERROR; 907 break; 908 } 909 } 910 } else if (line[0] == 'I') { 911 strlcpy(indent+2, line + 1, sizeof(indent) - 2); 912 } else if (line[0] >= 'a' && line[0] <= 'z') { 913 strcpy(last, line); 914 while ((i = getline(cfp)) != 0) 915 if (strcmp(last, line)) 916 break; 917 switch (sendfile(pp, '\3', last+1, *last)) { 918 case OK: 919 if (i) 920 goto again; 921 break; 922 case REPRINT: 923 (void) fclose(cfp); 924 return(REPRINT); 925 case ACCESS: 926 sendmail(pp, logname, ACCESS); 927 case ERROR: 928 err = ERROR; 929 } 930 break; 931 } 932 } 933 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 934 (void) fclose(cfp); 935 return(REPRINT); 936 } 937 /* 938 * pass 2 939 */ 940 fseek(cfp, 0L, 0); 941 while (getline(cfp)) 942 if (line[0] == 'U' && !strchr(line+1, '/')) 943 (void) unlink(line+1); 944 /* 945 * clean-up in case another control file exists 946 */ 947 (void) fclose(cfp); 948 (void) unlink(file); 949 return(err); 950} 951 952/* 953 * Send a data file to the remote machine and spool it. 954 * Return positive if we should try resending. 955 */ 956static int 957sendfile(struct printer *pp, int type, char *file, char format) 958{ 959 register int f, i, amt; 960 struct stat stb; 961 FILE *fp; 962 char buf[BUFSIZ]; 963 int closedpr, resp, sizerr, statrc; 964 965 statrc = lstat(file, &stb); 966 if (statrc < 0) { 967 syslog(LOG_ERR, "%s: error from lstat(%s): %m", 968 pp->printer, file); 969 return(ERROR); 970 } 971 f = open(file, O_RDONLY); 972 if (f < 0) { 973 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 974 pp->printer, file); 975 return(ERROR); 976 } 977 /* 978 * Check to see if data file is a symbolic link. If so, it should 979 * still point to the same file or someone is trying to print something 980 * he shouldn't. 981 */ 982 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 983 (stb.st_dev != fdev || stb.st_ino != fino)) 984 return(ACCESS); 985 986 job_dfcnt++; /* increment datafile counter for this job */ 987 988 /* everything seems OK, start it up */ 989 sizerr = 0; 990 closedpr = 0; 991 if (type == '\3') { 992 if (pp->filters[LPF_INPUT]) { 993 /* 994 * We're sending something with an ifilter. We have to 995 * run the ifilter and store the output as a temporary 996 * spool file (tfile...), because the protocol requires 997 * us to send the file size before we start sending any 998 * of the data. 999 */ 1000 char *av[15]; 1001 int n; 1002 int ifilter; 1003 union wait status; /* XXX */ 1004 1005 strcpy(tfile,TFILENAME); 1006 if ((tfd = mkstemp(tfile)) == -1) { 1007 syslog(LOG_ERR, "mkstemp: %m"); 1008 return(ERROR); 1009 } 1010 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 1011 av[0] = pp->filters[LPF_INPUT]; 1012 else 1013 av[0]++; 1014 if (format == 'l') 1015 av[n=1] = "-c"; 1016 else 1017 n = 0; 1018 av[++n] = width; 1019 av[++n] = length; 1020 av[++n] = indent; 1021 av[++n] = "-n"; 1022 av[++n] = logname; 1023 av[++n] = "-h"; 1024 av[++n] = origin_host; 1025 av[++n] = pp->acct_file; 1026 av[++n] = 0; 1027 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 1028 dup2(f, 0); 1029 dup2(tfd, 1); 1030 /* setup stderr for the filter (child process) 1031 * so it goes to our temporary errors file */ 1032 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1033 if (n >= 0) 1034 dup2(n, 2); 1035 closelog(); 1036 closeallfds(3); 1037 execv(pp->filters[LPF_INPUT], av); 1038 syslog(LOG_ERR, "cannot execv %s", 1039 pp->filters[LPF_INPUT]); 1040 exit(2); 1041 } 1042 (void) close(f); 1043 if (ifilter < 0) 1044 status.w_retcode = 100; 1045 else { 1046 while ((pid = wait((int *)&status)) > 0 && 1047 pid != ifilter) 1048 ; 1049 if (pid < 0) { 1050 status.w_retcode = 100; 1051 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 1052 pp->printer, pp->filters[LPF_INPUT]); 1053 } 1054 } 1055 /* Copy the filter's output to "lf" logfile */ 1056 if ((fp = fopen(tempstderr, "r"))) { 1057 while (fgets(buf, sizeof(buf), fp)) 1058 fputs(buf, stderr); 1059 fclose(fp); 1060 } 1061 /* process the return-code from the filter */ 1062 switch (status.w_retcode) { 1063 case 0: 1064 break; 1065 case 1: 1066 unlink(tfile); 1067 return(REPRINT); 1068 case 2: 1069 unlink(tfile); 1070 return(ERROR); 1071 default: 1072 syslog(LOG_WARNING, "%s: filter '%c' exited" 1073 " (retcode=%d)", 1074 pp->printer, format, status.w_retcode); 1075 unlink(tfile); 1076 return(FILTERERR); 1077 } 1078 statrc = fstat(tfd, &stb); /* to find size of tfile */ 1079 if (statrc < 0) { 1080 syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m", 1081 pp->printer, tfile); 1082 return(ERROR); 1083 } 1084 f = tfd; 1085 lseek(f,0,SEEK_SET); 1086 } else if (ofilter) { 1087 /* 1088 * We're sending something with an ofilter, we have to 1089 * store the output as a temporary file (tfile)... the 1090 * protocol requires us to send the file size 1091 */ 1092 int i; 1093 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1094 amt = BUFSIZ; 1095 if (i + amt > stb.st_size) 1096 amt = stb.st_size - i; 1097 if (sizerr == 0 && read(f, buf, amt) != amt) { 1098 sizerr = 1; 1099 break; 1100 } 1101 if (write(ofd, buf, amt) != amt) { 1102 (void) close(f); 1103 return(REPRINT); 1104 } 1105 } 1106 close(ofd); 1107 close(f); 1108 while ((i = wait(NULL)) > 0 && i != ofilter) 1109 ; 1110 if (i < 0) 1111 syslog(LOG_WARNING, "%s: after closing 'of', wait() returned: %m", 1112 pp->printer); 1113 ofilter = 0; 1114 statrc = fstat(tfd, &stb); /* to find size of tfile */ 1115 if (statrc < 0) { 1116 syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m", 1117 pp->printer, tfile); 1118 openpr(pp); 1119 return(ERROR); 1120 } 1121 f = tfd; 1122 lseek(f,0,SEEK_SET); 1123 closedpr = 1; 1124 } 1125 } 1126 1127 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1128 amt = strlen(buf); 1129 for (i = 0; ; i++) { 1130 if (write(pfd, buf, amt) != amt || 1131 (resp = response(pp)) < 0 || resp == '\1') { 1132 (void) close(f); 1133 if (tfd != -1 && type == '\3') { 1134 tfd = -1; 1135 unlink(tfile); 1136 if (closedpr) 1137 openpr(pp); 1138 } 1139 return(REPRINT); 1140 } else if (resp == '\0') 1141 break; 1142 if (i == 0) 1143 pstatus(pp, 1144 "no space on remote; waiting for queue to drain"); 1145 if (i == 10) 1146 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1147 pp->printer, pp->remote_host); 1148 sleep(5 * 60); 1149 } 1150 if (i) 1151 pstatus(pp, "sending to %s", pp->remote_host); 1152 if (type == '\3') 1153 trstat_init(pp, file, job_dfcnt); 1154 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1155 amt = BUFSIZ; 1156 if (i + amt > stb.st_size) 1157 amt = stb.st_size - i; 1158 if (sizerr == 0 && read(f, buf, amt) != amt) 1159 sizerr = 1; 1160 if (write(pfd, buf, amt) != amt) { 1161 (void) close(f); 1162 if (tfd != -1 && type == '\3') { 1163 tfd = -1; 1164 unlink(tfile); 1165 if (closedpr) 1166 openpr(pp); 1167 } 1168 return(REPRINT); 1169 } 1170 } 1171 1172 (void) close(f); 1173 if (tfd != -1 && type == '\3') { 1174 tfd = -1; 1175 unlink(tfile); 1176 } 1177 if (sizerr) { 1178 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1179 /* tell recvjob to ignore this file */ 1180 (void) write(pfd, "\1", 1); 1181 if (closedpr) 1182 openpr(pp); 1183 return(ERROR); 1184 } 1185 if (write(pfd, "", 1) != 1 || response(pp)) { 1186 if (closedpr) 1187 openpr(pp); 1188 return(REPRINT); 1189 } 1190 if (closedpr) 1191 openpr(pp); 1192 if (type == '\3') 1193 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1194 pp->remote_host, origin_host); 1195 return(OK); 1196} 1197 1198/* 1199 * Check to make sure there have been no errors and that both programs 1200 * are in sync with eachother. 1201 * Return non-zero if the connection was lost. 1202 */ 1203static char 1204response(const struct printer *pp) 1205{ 1206 char resp; 1207 1208 if (read(pfd, &resp, 1) != 1) { 1209 syslog(LOG_INFO, "%s: lost connection", pp->printer); 1210 return(-1); 1211 } 1212 return(resp); 1213} 1214 1215/* 1216 * Banner printing stuff 1217 */ 1218static void 1219banner(struct printer *pp, char *name1, char *name2) 1220{ 1221 time_t tvec; 1222 1223 time(&tvec); 1224 if (!pp->no_formfeed && !pp->tof) 1225 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1226 if (pp->short_banner) { /* short banner only */ 1227 if (class[0]) { 1228 (void) write(ofd, class, strlen(class)); 1229 (void) write(ofd, ":", 1); 1230 } 1231 (void) write(ofd, name1, strlen(name1)); 1232 (void) write(ofd, " Job: ", 7); 1233 (void) write(ofd, name2, strlen(name2)); 1234 (void) write(ofd, " Date: ", 8); 1235 (void) write(ofd, ctime(&tvec), 24); 1236 (void) write(ofd, "\n", 1); 1237 } else { /* normal banner */ 1238 (void) write(ofd, "\n\n\n", 3); 1239 scan_out(pp, ofd, name1, '\0'); 1240 (void) write(ofd, "\n\n", 2); 1241 scan_out(pp, ofd, name2, '\0'); 1242 if (class[0]) { 1243 (void) write(ofd,"\n\n\n",3); 1244 scan_out(pp, ofd, class, '\0'); 1245 } 1246 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1247 (void) write(ofd, name2, strlen(name2)); 1248 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1249 (void) write(ofd, ctime(&tvec), 24); 1250 (void) write(ofd, "\n", 1); 1251 } 1252 if (!pp->no_formfeed) 1253 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1254 pp->tof = 1; 1255} 1256 1257static char * 1258scnline(int key, char *p, int c) 1259{ 1260 register int scnwidth; 1261 1262 for (scnwidth = WIDTH; --scnwidth;) { 1263 key <<= 1; 1264 *p++ = key & 0200 ? c : BACKGND; 1265 } 1266 return (p); 1267} 1268 1269#define TRC(q) (((q)-' ')&0177) 1270 1271static void 1272scan_out(struct printer *pp, int scfd, char *scsp, int dlm) 1273{ 1274 register char *strp; 1275 register int nchrs, j; 1276 char outbuf[LINELEN+1], *sp, c, cc; 1277 int d, scnhgt; 1278 1279 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1280 strp = &outbuf[0]; 1281 sp = scsp; 1282 for (nchrs = 0; ; ) { 1283 d = dropit(c = TRC(cc = *sp++)); 1284 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1285 for (j = WIDTH; --j;) 1286 *strp++ = BACKGND; 1287 else 1288 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1289 if (*sp == dlm || *sp == '\0' || 1290 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1291 break; 1292 *strp++ = BACKGND; 1293 *strp++ = BACKGND; 1294 } 1295 while (*--strp == BACKGND && strp >= outbuf) 1296 ; 1297 strp++; 1298 *strp++ = '\n'; 1299 (void) write(scfd, outbuf, strp-outbuf); 1300 } 1301} 1302 1303static int 1304dropit(int c) 1305{ 1306 switch(c) { 1307 1308 case TRC('_'): 1309 case TRC(';'): 1310 case TRC(','): 1311 case TRC('g'): 1312 case TRC('j'): 1313 case TRC('p'): 1314 case TRC('q'): 1315 case TRC('y'): 1316 return (DROP); 1317 1318 default: 1319 return (0); 1320 } 1321} 1322 1323/* 1324 * sendmail --- 1325 * tell people about job completion 1326 */ 1327static void 1328sendmail(struct printer *pp, char *user, int bombed) 1329{ 1330 register int i; 1331 int p[2], s; 1332 register const char *cp; 1333 struct stat stb; 1334 FILE *fp; 1335 1336 pipe(p); 1337 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1338 dup2(p[0], 0); 1339 closelog(); 1340 closeallfds(3); 1341 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1342 cp++; 1343 else 1344 cp = _PATH_SENDMAIL; 1345 execl(_PATH_SENDMAIL, cp, "-t", (char *)0); 1346 _exit(0); 1347 } else if (s > 0) { /* parent */ 1348 dup2(p[1], 1); 1349 printf("To: %s@%s\n", user, origin_host); 1350 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1351 *jobname ? jobname : "<unknown>"); 1352 printf("Reply-To: root@%s\n\n", local_host); 1353 printf("Your printer job "); 1354 if (*jobname) 1355 printf("(%s) ", jobname); 1356 1357 cp = "XXX compiler confusion"; /* XXX shut GCC up */ 1358 switch (bombed) { 1359 case OK: 1360 printf("\ncompleted successfully\n"); 1361 cp = "OK"; 1362 break; 1363 default: 1364 case FATALERR: 1365 printf("\ncould not be printed\n"); 1366 cp = "FATALERR"; 1367 break; 1368 case NOACCT: 1369 printf("\ncould not be printed without an account on %s\n", 1370 local_host); 1371 cp = "NOACCT"; 1372 break; 1373 case FILTERERR: 1374 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1375 || (fp = fopen(tempstderr, "r")) == NULL) { 1376 printf("\nhad some errors and may not have printed\n"); 1377 break; 1378 } 1379 printf("\nhad the following errors and may not have printed:\n"); 1380 while ((i = getc(fp)) != EOF) 1381 putchar(i); 1382 (void) fclose(fp); 1383 cp = "FILTERERR"; 1384 break; 1385 case ACCESS: 1386 printf("\nwas not printed because it was not linked to the original file\n"); 1387 cp = "ACCESS"; 1388 } 1389 fflush(stdout); 1390 (void) close(1); 1391 } else { 1392 syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 1393 return; 1394 } 1395 (void) close(p[0]); 1396 (void) close(p[1]); 1397 wait(NULL); 1398 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1399 user, *jobname ? jobname : "<unknown>", pp->printer, cp); 1400} 1401 1402/* 1403 * dofork - fork with retries on failure 1404 */ 1405static int 1406dofork(const struct printer *pp, int action) 1407{ 1408 int i, fail, forkpid; 1409 struct passwd *pwd; 1410 1411 forkpid = -1; 1412 if (daemon_uname == NULL) { 1413 pwd = getpwuid(pp->daemon_user); 1414 if (pwd == NULL) { 1415 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file", 1416 pp->printer, pp->daemon_user); 1417 goto error_ret; 1418 } 1419 daemon_uname = strdup(pwd->pw_name); 1420 daemon_defgid = pwd->pw_gid; 1421 } 1422 1423 for (i = 0; i < 20; i++) { 1424 forkpid = fork(); 1425 if (forkpid < 0) { 1426 sleep((unsigned)(i*i)); 1427 continue; 1428 } 1429 /* 1430 * Child should run as daemon instead of root 1431 */ 1432 if (forkpid == 0) { 1433 errno = 0; 1434 fail = initgroups(daemon_uname, daemon_defgid); 1435 if (fail) { 1436 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m", 1437 pp->printer, daemon_uname, daemon_defgid); 1438 break; 1439 } 1440 fail = setgid(daemon_defgid); 1441 if (fail) { 1442 syslog(LOG_ERR, "%s: setgid(%u): %m", 1443 pp->printer, daemon_defgid); 1444 break; 1445 } 1446 fail = setuid(pp->daemon_user); 1447 if (fail) { 1448 syslog(LOG_ERR, "%s: setuid(%ld): %m", 1449 pp->printer, pp->daemon_user); 1450 break; 1451 } 1452 } 1453 return forkpid; 1454 } 1455 1456 /* 1457 * An error occurred. If the error is in the child process, then 1458 * this routine MUST always exit(). DORETURN only effects how 1459 * errors should be handled in the parent process. 1460 */ 1461error_ret: 1462 if (forkpid == 0) { 1463 syslog(LOG_ERR, "%s: dofork(): aborting child process...", 1464 pp->printer); 1465 exit(1); 1466 } 1467 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer); 1468 1469 sleep(1); /* throttle errors, as a safety measure */ 1470 switch (action) { 1471 case DORETURN: 1472 return -1; 1473 default: 1474 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1475 /* FALLTHROUGH */ 1476 case DOABORT: 1477 exit(1); 1478 } 1479 /*NOTREACHED*/ 1480} 1481 1482/* 1483 * Kill child processes to abort current job. 1484 */ 1485static void 1486abortpr(int signo __unused) 1487{ 1488 1489 (void) unlink(tempstderr); 1490 kill(0, SIGINT); 1491 if (ofilter > 0) 1492 kill(ofilter, SIGCONT); 1493 while (wait(NULL) > 0) 1494 ; 1495 if (ofilter > 0 && tfd != -1) 1496 unlink(tfile); 1497 exit(0); 1498} 1499 1500static void 1501init(struct printer *pp) 1502{ 1503 char *s; 1504 1505 sprintf(&width[2], "%ld", pp->page_width); 1506 sprintf(&length[2], "%ld", pp->page_length); 1507 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1508 sprintf(&pxlength[2], "%ld", pp->page_plength); 1509 if ((s = checkremote(pp)) != 0) { 1510 syslog(LOG_WARNING, "%s", s); 1511 free(s); 1512 } 1513} 1514 1515void 1516startprinting(const char *printer) 1517{ 1518 struct printer myprinter, *pp = &myprinter; 1519 int status; 1520 1521 init_printer(pp); 1522 status = getprintcap(printer, pp); 1523 switch(status) { 1524 case PCAPERR_OSERR: 1525 syslog(LOG_ERR, "can't open printer description file: %m"); 1526 exit(1); 1527 case PCAPERR_NOTFOUND: 1528 syslog(LOG_ERR, "unknown printer: %s", printer); 1529 exit(1); 1530 case PCAPERR_TCLOOP: 1531 fatal(pp, "potential reference loop detected in printcap file"); 1532 default: 1533 break; 1534 } 1535 printjob(pp); 1536} 1537 1538/* 1539 * Acquire line printer or remote connection. 1540 */ 1541static void 1542openpr(const struct printer *pp) 1543{ 1544 int p[2]; 1545 char *cp; 1546 1547 if (pp->remote) { 1548 openrem(pp); 1549 } else if (*pp->lp) { 1550 if ((cp = strchr(pp->lp, '@')) != NULL) 1551 opennet(pp); 1552 else 1553 opentty(pp); 1554 } else { 1555 syslog(LOG_ERR, "%s: no line printer device or host name", 1556 pp->printer); 1557 exit(1); 1558 } 1559 1560 /* 1561 * Start up an output filter, if needed. 1562 */ 1563 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1564 pipe(p); 1565 if (pp->remote) { 1566 strcpy(tfile, TFILENAME); 1567 tfd = mkstemp(tfile); 1568 } 1569 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1570 dup2(p[0], 0); /* pipe is std in */ 1571 /* tfile/printer is stdout */ 1572 dup2(pp->remote ? tfd : pfd, 1); 1573 closelog(); 1574 closeallfds(3); 1575 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1576 cp = pp->filters[LPF_OUTPUT]; 1577 else 1578 cp++; 1579 execl(pp->filters[LPF_OUTPUT], cp, width, length, 1580 (char *)0); 1581 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1582 pp->filters[LPF_OUTPUT]); 1583 exit(1); 1584 } 1585 (void) close(p[0]); /* close input side */ 1586 ofd = p[1]; /* use pipe for output */ 1587 } else { 1588 ofd = pfd; 1589 ofilter = 0; 1590 } 1591} 1592 1593/* 1594 * Printer connected directly to the network 1595 * or to a terminal server on the net 1596 */ 1597static void 1598opennet(const struct printer *pp) 1599{ 1600 register int i; 1601 int resp; 1602 u_long port; 1603 char *ep; 1604 void (*savealrm)(int); 1605 1606 port = strtoul(pp->lp, &ep, 0); 1607 if (*ep != '@' || port > 65535) { 1608 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1609 pp->lp); 1610 exit(1); 1611 } 1612 ep++; 1613 1614 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1615 resp = -1; 1616 savealrm = signal(SIGALRM, alarmhandler); 1617 alarm(pp->conn_timeout); 1618 pfd = getport(pp, ep, port); 1619 alarm(0); 1620 (void)signal(SIGALRM, savealrm); 1621 if (pfd < 0 && errno == ECONNREFUSED) 1622 resp = 1; 1623 else if (pfd >= 0) { 1624 /* 1625 * need to delay a bit for rs232 lines 1626 * to stabilize in case printer is 1627 * connected via a terminal server 1628 */ 1629 delay(500); 1630 break; 1631 } 1632 if (i == 1) { 1633 if (resp < 0) 1634 pstatus(pp, "waiting for %s to come up", 1635 pp->lp); 1636 else 1637 pstatus(pp, 1638 "waiting for access to printer on %s", 1639 pp->lp); 1640 } 1641 sleep(i); 1642 } 1643 pstatus(pp, "sending to %s port %lu", ep, port); 1644} 1645 1646/* 1647 * Printer is connected to an RS232 port on this host 1648 */ 1649static void 1650opentty(const struct printer *pp) 1651{ 1652 register int i; 1653 1654 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1655 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1656 if (pfd >= 0) { 1657 delay(500); 1658 break; 1659 } 1660 if (errno == ENOENT) { 1661 syslog(LOG_ERR, "%s: %m", pp->lp); 1662 exit(1); 1663 } 1664 if (i == 1) 1665 pstatus(pp, 1666 "waiting for %s to become ready (offline?)", 1667 pp->printer); 1668 sleep(i); 1669 } 1670 if (isatty(pfd)) 1671 setty(pp); 1672 pstatus(pp, "%s is ready and printing", pp->printer); 1673} 1674 1675/* 1676 * Printer is on a remote host 1677 */ 1678static void 1679openrem(const struct printer *pp) 1680{ 1681 register int i; 1682 int resp; 1683 void (*savealrm)(int); 1684 1685 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1686 resp = -1; 1687 savealrm = signal(SIGALRM, alarmhandler); 1688 alarm(pp->conn_timeout); 1689 pfd = getport(pp, pp->remote_host, 0); 1690 alarm(0); 1691 (void)signal(SIGALRM, savealrm); 1692 if (pfd >= 0) { 1693 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1694 (char *)0) 1695 == 2 + strlen(pp->remote_queue)) 1696 && (resp = response(pp)) == 0) 1697 break; 1698 (void) close(pfd); 1699 } 1700 if (i == 1) { 1701 if (resp < 0) 1702 pstatus(pp, "waiting for %s to come up", 1703 pp->remote_host); 1704 else { 1705 pstatus(pp, 1706 "waiting for queue to be enabled on %s", 1707 pp->remote_host); 1708 i = 256; 1709 } 1710 } 1711 sleep(i); 1712 } 1713 pstatus(pp, "sending to %s", pp->remote_host); 1714} 1715 1716/* 1717 * setup tty lines. 1718 */ 1719static void 1720setty(const struct printer *pp) 1721{ 1722 struct termios ttybuf; 1723 1724 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1725 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1726 exit(1); 1727 } 1728 if (tcgetattr(pfd, &ttybuf) < 0) { 1729 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1730 exit(1); 1731 } 1732 if (pp->baud_rate > 0) 1733 cfsetspeed(&ttybuf, pp->baud_rate); 1734 if (pp->mode_set) { 1735 char *s = strdup(pp->mode_set), *tmp; 1736 1737 while ((tmp = strsep(&s, ",")) != NULL) { 1738 (void) msearch(tmp, &ttybuf); 1739 } 1740 } 1741 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1742 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1743 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1744 } 1745 } 1746} 1747 1748#ifdef __STDC__ 1749#include <stdarg.h> 1750#else 1751#include <varargs.h> 1752#endif 1753 1754static void 1755#ifdef __STDC__ 1756pstatus(const struct printer *pp, const char *msg, ...) 1757#else 1758pstatus(pp, msg, va_alist) 1759 const struct printer *pp; 1760 char *msg; 1761 va_dcl 1762#endif 1763{ 1764 int fd; 1765 char *buf; 1766 va_list ap; 1767#ifdef __STDC__ 1768 va_start(ap, msg); 1769#else 1770 va_start(ap); 1771#endif 1772 1773 umask(0); 1774 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1775 if (fd < 0) { 1776 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1777 exit(1); 1778 } 1779 ftruncate(fd, 0); 1780 vasprintf(&buf, msg, ap); 1781 va_end(ap); 1782 writel(fd, buf, "\n", (char *)0); 1783 close(fd); 1784 free(buf); 1785} 1786 1787void 1788alarmhandler(int signo __unused) 1789{ 1790 /* the signal is ignored */ 1791 /* (the '__unused' is just to avoid a compile-time warning) */ 1792} 1793