printjob.c revision 211190
1189251Ssam/* 2189251Ssam * Copyright (c) 1983, 1993 3281806Srpaulo * The Regents of the University of California. All rights reserved. 4189251Ssam * 5252726Srpaulo * 6252726Srpaulo * Redistribution and use in source and binary forms, with or without 7189251Ssam * modification, are permitted provided that the following conditions 8189251Ssam * are met: 9189251Ssam * 1. Redistributions of source code must retain the above copyright 10189251Ssam * notice, this list of conditions and the following disclaimer. 11189251Ssam * 2. Redistributions in binary form must reproduce the above copyright 12189251Ssam * notice, this list of conditions and the following disclaimer in the 13189251Ssam * documentation and/or other materials provided with the distribution. 14189251Ssam * 3. All advertising materials mentioning features or use of this software 15189251Ssam * must display the following acknowledgement: 16189251Ssam * This product includes software developed by the University of 17214734Srpaulo * California, Berkeley and its contributors. 18252726Srpaulo * 4. Neither the name of the University nor the names of its contributors 19252726Srpaulo * may be used to endorse or promote products derived from this software 20252726Srpaulo * without specific prior written permission. 21252726Srpaulo * 22214734Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23252726Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24252726Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25252726Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26252726Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31281806Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32189251Ssam * SUCH DAMAGE. 33189251Ssam */ 34189251Ssam 35252726Srpaulo#ifndef lint 36252726Srpaulostatic const char copyright[] = 37189251Ssam"@(#) Copyright (c) 1983, 1993\n\ 38189251Ssam The Regents of the University of California. All rights reserved.\n"; 39252726Srpaulo#endif /* not lint */ 40189251Ssam 41189251Ssam#if 0 42189251Ssam#ifndef lint 43189251Ssamstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 44189251Ssam#endif /* not lint */ 45189251Ssam#endif 46189251Ssam 47189251Ssam#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 48189251Ssam__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 211190 2010-08-11 19:32:49Z gad $"); 49189251Ssam 50189251Ssam/* 51189251Ssam * printjob -- print jobs in the queue. 52189251Ssam * 53189251Ssam * NOTE: the lock file is used to pass information to lpq and lprm. 54189251Ssam * it does not need to be removed because file locks are dynamic. 55189251Ssam */ 56189251Ssam 57189251Ssam#include <sys/param.h> 58189251Ssam#include <sys/wait.h> 59189251Ssam#include <sys/stat.h> 60189251Ssam#include <sys/types.h> 61189251Ssam 62189251Ssam#include <pwd.h> 63189251Ssam#include <unistd.h> 64189251Ssam#include <signal.h> 65189251Ssam#include <syslog.h> 66189251Ssam#include <fcntl.h> 67189251Ssam#include <dirent.h> 68189251Ssam#include <errno.h> 69189251Ssam#include <stdio.h> 70214734Srpaulo#include <string.h> 71189251Ssam#include <stdlib.h> 72189251Ssam#include <sys/ioctl.h> 73281806Srpaulo#include <termios.h> 74189251Ssam#include <time.h> 75252726Srpaulo#include "lp.h" 76252726Srpaulo#include "lp.local.h" 77252726Srpaulo#include "pathnames.h" 78252726Srpaulo#include "extern.h" 79189251Ssam 80189251Ssam#define DORETURN 0 /* dofork should return "can't fork" error */ 81189251Ssam#define DOABORT 1 /* dofork should just die if fork() fails */ 82189251Ssam 83214734Srpaulo/* 84281806Srpaulo * The buffer size to use when reading/writing spool files. 85189251Ssam */ 86252726Srpaulo#define SPL_BUFSIZ BUFSIZ 87252726Srpaulo 88252726Srpaulo/* 89252726Srpaulo * Error tokens 90189251Ssam */ 91252726Srpaulo#define REPRINT -2 92252726Srpaulo#define ERROR -1 93252726Srpaulo#define OK 0 94281806Srpaulo#define FATALERR 1 95189251Ssam#define NOACCT 2 96189251Ssam#define FILTERERR 3 97252726Srpaulo#define ACCESS 4 98252726Srpaulo 99252726Srpaulostatic dev_t fdev; /* device of file pointed to by symlink */ 100252726Srpaulostatic ino_t fino; /* inode of file pointed to by symlink */ 101252726Srpaulostatic FILE *cfp; /* control file */ 102252726Srpaulostatic pid_t of_pid; /* process id of output filter, if any */ 103252726Srpaulostatic int child; /* id of any filters */ 104189251Ssamstatic int job_dfcnt; /* count of datafiles in current user job */ 105189251Ssamstatic int lfd; /* lock file descriptor */ 106189251Ssamstatic int ofd; /* output filter file descriptor */ 107189251Ssamstatic int tfd = -1; /* output filter temp file output */ 108189251Ssamstatic int pfd; /* prstatic inter file descriptor */ 109189251Ssamstatic int prchild; /* id of pr process */ 110189251Ssamstatic char title[80]; /* ``pr'' title */ 111189251Ssamstatic char locale[80]; /* ``pr'' locale */ 112189251Ssam 113189251Ssam/* these two are set from pp->daemon_user, but only if they are needed */ 114189251Ssamstatic char *daemon_uname; /* set from pwd->pw_name */ 115189251Ssamstatic int daemon_defgid; 116252726Srpaulo 117189251Ssamstatic char class[32]; /* classification field */ 118252726Srpaulostatic char origin_host[MAXHOSTNAMELEN]; /* user's host machine */ 119189251Ssam /* indentation size in static characters */ 120189251Ssamstatic char indent[10] = "-i0"; 121189251Ssamstatic char jobname[100]; /* job or file name */ 122252726Srpaulostatic char length[10] = "-l"; /* page length in lines */ 123252726Srpaulostatic char logname[32]; /* user's login name */ 124252726Srpaulostatic char pxlength[10] = "-y"; /* page length in pixels */ 125252726Srpaulostatic char pxwidth[10] = "-x"; /* page width in pixels */ 126252726Srpaulo/* tempstderr is the filename used to catch stderr from exec-ing filters */ 127252726Srpaulostatic char tempstderr[] = "errs.XXXXXXX"; 128214734Srpaulostatic char width[10] = "-w"; /* page width in static characters */ 129252726Srpaulo#define TFILENAME "fltXXXXXX" 130252726Srpaulostatic char tfile[] = TFILENAME; /* file name for filter output */ 131189251Ssam 132252726Srpaulostatic void abortpr(int _signo); 133252726Srpaulostatic void alarmhandler(int _signo); 134252726Srpaulostatic void banner(struct printer *_pp, char *_name1, char *_name2); 135214734Srpaulostatic int dofork(const struct printer *_pp, int _action); 136214734Srpaulostatic int dropit(int _c); 137252726Srpaulostatic int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av, 138252726Srpaulo int _infd, int _outfd); 139252726Srpaulostatic void init(struct printer *_pp); 140214734Srpaulostatic void openpr(const struct printer *_pp); 141252726Srpaulostatic void opennet(const struct printer *_pp); 142252726Srpaulostatic void opentty(const struct printer *_pp); 143252726Srpaulostatic void openrem(const struct printer *pp); 144252726Srpaulostatic int print(struct printer *_pp, int _format, char *_file); 145252726Srpaulostatic int printit(struct printer *_pp, char *_file); 146252726Srpaulostatic void pstatus(const struct printer *_pp, const char *_msg, ...) 147252726Srpaulo __printflike(2, 3); 148214734Srpaulostatic char response(const struct printer *_pp); 149214734Srpaulostatic void scan_out(struct printer *_pp, int _scfd, char *_scsp, 150252726Srpaulo int _dlm); 151252726Srpaulostatic char *scnline(int _key, char *_p, int _c); 152252726Srpaulostatic int sendfile(struct printer *_pp, int _type, char *_file, 153252726Srpaulo char _format, int _copyreq); 154252726Srpaulostatic int sendit(struct printer *_pp, char *_file); 155252726Srpaulostatic void sendmail(struct printer *_pp, char *_userid, int _bombed); 156252726Srpaulostatic void setty(const struct printer *_pp); 157252726Srpaulostatic void wait4data(struct printer *_pp, const char *_dfile); 158252726Srpaulo 159252726Srpaulovoid 160252726Srpauloprintjob(struct printer *pp) 161252726Srpaulo{ 162252726Srpaulo struct stat stb; 163252726Srpaulo register struct jobqueue *q, **qp; 164252726Srpaulo struct jobqueue **queue; 165252726Srpaulo register int i, nitems; 166252726Srpaulo off_t pidoff; 167252726Srpaulo pid_t printpid; 168252726Srpaulo int errcnt, jobcount, statok, tempfd; 169252726Srpaulo 170252726Srpaulo jobcount = 0; 171252726Srpaulo init(pp); /* set up capabilities */ 172252726Srpaulo (void) write(STDOUT_FILENO, "", 1); /* ack that daemon is started */ 173252726Srpaulo (void) close(STDERR_FILENO); /* set up log file */ 174252726Srpaulo if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 175252726Srpaulo syslog(LOG_ERR, "%s: open(%s): %m", pp->printer, 176252726Srpaulo pp->log_file); 177252726Srpaulo (void) open(_PATH_DEVNULL, O_WRONLY); 178281806Srpaulo } 179252726Srpaulo setgid(getegid()); 180252726Srpaulo printpid = getpid(); /* for use with lprm */ 181252726Srpaulo setpgrp(0, printpid); 182252726Srpaulo 183252726Srpaulo /* 184252726Srpaulo * At initial lpd startup, printjob may be called with various 185252726Srpaulo * signal handlers in effect. After that initial startup, any 186252726Srpaulo * calls to printjob will have a *different* set of signal-handlers 187252726Srpaulo * in effect. Make sure all handlers are the ones we want. 188252726Srpaulo */ 189252726Srpaulo signal(SIGCHLD, SIG_DFL); 190252726Srpaulo signal(SIGHUP, abortpr); 191252726Srpaulo signal(SIGINT, abortpr); 192252726Srpaulo signal(SIGQUIT, abortpr); 193252726Srpaulo signal(SIGTERM, abortpr); 194252726Srpaulo 195252726Srpaulo /* 196252726Srpaulo * uses short form file names 197252726Srpaulo */ 198252726Srpaulo if (chdir(pp->spool_dir) < 0) { 199252726Srpaulo syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer, 200252726Srpaulo pp->spool_dir); 201252726Srpaulo exit(1); 202252726Srpaulo } 203252726Srpaulo statok = stat(pp->lock_file, &stb); 204252726Srpaulo if (statok == 0 && (stb.st_mode & LFM_PRINT_DIS)) 205252726Srpaulo exit(0); /* printing disabled */ 206252726Srpaulo umask(S_IWOTH); 207252726Srpaulo lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 208252726Srpaulo LOCK_FILE_MODE); 209252726Srpaulo if (lfd < 0) { 210252726Srpaulo if (errno == EWOULDBLOCK) /* active daemon present */ 211252726Srpaulo exit(0); 212252726Srpaulo syslog(LOG_ERR, "%s: open(%s): %m", pp->printer, 213252726Srpaulo pp->lock_file); 214252726Srpaulo exit(1); 215252726Srpaulo } 216252726Srpaulo /* 217252726Srpaulo * If the initial call to stat() failed, then lock_file will have 218252726Srpaulo * been created by open(). Update &stb to match that new file. 219252726Srpaulo */ 220252726Srpaulo if (statok != 0) 221252726Srpaulo statok = stat(pp->lock_file, &stb); 222252726Srpaulo /* turn off non-blocking mode (was turned on for lock effects only) */ 223252726Srpaulo if (fcntl(lfd, F_SETFL, 0) < 0) { 224252726Srpaulo syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer, 225252726Srpaulo pp->lock_file); 226281806Srpaulo exit(1); 227252726Srpaulo } 228252726Srpaulo ftruncate(lfd, 0); 229252726Srpaulo /* 230252726Srpaulo * write process id for others to know 231252726Srpaulo */ 232252726Srpaulo sprintf(line, "%u\n", printpid); 233252726Srpaulo pidoff = i = strlen(line); 234252726Srpaulo if (write(lfd, line, i) != i) { 235252726Srpaulo syslog(LOG_ERR, "%s: write(%s): %m", pp->printer, 236252726Srpaulo pp->lock_file); 237252726Srpaulo exit(1); 238252726Srpaulo } 239252726Srpaulo /* 240252726Srpaulo * search the spool directory for work and sort by queue order. 241252726Srpaulo */ 242252726Srpaulo if ((nitems = getq(pp, &queue)) < 0) { 243252726Srpaulo syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 244252726Srpaulo pp->spool_dir); 245252726Srpaulo exit(1); 246252726Srpaulo } 247252726Srpaulo if (nitems == 0) /* no work to do */ 248252726Srpaulo exit(0); 249252726Srpaulo if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 250214734Srpaulo if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 251252726Srpaulo syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 252252726Srpaulo pp->lock_file); 253252726Srpaulo } 254252726Srpaulo 255252726Srpaulo /* create a file which will be used to hold stderr from filters */ 256252726Srpaulo if ((tempfd = mkstemp(tempstderr)) == -1) { 257252726Srpaulo syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 258252726Srpaulo tempstderr); 259252726Srpaulo exit(1); 260252726Srpaulo } 261252726Srpaulo if ((i = fchmod(tempfd, 0664)) == -1) { 262252726Srpaulo syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 263252726Srpaulo tempstderr); 264252726Srpaulo exit(1); 265252726Srpaulo } 266252726Srpaulo /* lpd doesn't need it to be open, it just needs it to exist */ 267214734Srpaulo close(tempfd); 268214734Srpaulo 269252726Srpaulo openpr(pp); /* open printer or remote */ 270252726Srpauloagain: 271252726Srpaulo /* 272252726Srpaulo * we found something to do now do it -- 273214734Srpaulo * write the name of the current control file into the lock file 274214734Srpaulo * so the spool queue program can tell what we're working on 275214734Srpaulo */ 276252726Srpaulo for (qp = queue; nitems--; free((char *) q)) { 277252726Srpaulo q = *qp++; 278252726Srpaulo if (stat(q->job_cfname, &stb) < 0) 279252726Srpaulo continue; 280252726Srpaulo errcnt = 0; 281252726Srpaulo restart: 282252726Srpaulo (void) lseek(lfd, pidoff, 0); 283252726Srpaulo (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 284252726Srpaulo i = strlen(line); 285252726Srpaulo if (write(lfd, line, i) != i) 286252726Srpaulo syslog(LOG_ERR, "%s: write(%s): %m", pp->printer, 287252726Srpaulo pp->lock_file); 288252726Srpaulo if (!pp->remote) 289252726Srpaulo i = printit(pp, q->job_cfname); 290252726Srpaulo else 291252726Srpaulo i = sendit(pp, q->job_cfname); 292252726Srpaulo /* 293252726Srpaulo * Check to see if we are supposed to stop printing or 294252726Srpaulo * if we are to rebuild the queue. 295252726Srpaulo */ 296252726Srpaulo if (fstat(lfd, &stb) == 0) { 297252726Srpaulo /* stop printing before starting next job? */ 298252726Srpaulo if (stb.st_mode & LFM_PRINT_DIS) 299252726Srpaulo goto done; 300252726Srpaulo /* rebuild queue (after lpc topq) */ 301252726Srpaulo if (stb.st_mode & LFM_RESET_QUE) { 302252726Srpaulo for (free(q); nitems--; free(q)) 303214734Srpaulo q = *qp++; 304214734Srpaulo if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 305189251Ssam < 0) 306189251Ssam syslog(LOG_WARNING, 307214734Srpaulo "%s: fchmod(%s): %m", 308214734Srpaulo pp->printer, pp->lock_file); 309214734Srpaulo break; 310214734Srpaulo } 311214734Srpaulo } 312214734Srpaulo if (i == OK) /* all files of this job printed */ 313214734Srpaulo jobcount++; 314189251Ssam else if (i == REPRINT && ++errcnt < 5) { 315252726Srpaulo /* try reprinting the job */ 316189251Ssam syslog(LOG_INFO, "restarting %s", pp->printer); 317189251Ssam if (of_pid > 0) { 318189251Ssam kill(of_pid, SIGCONT); /* to be sure */ 319214734Srpaulo (void) close(ofd); 320189251Ssam while ((i = wait(NULL)) > 0 && i != of_pid) 321252726Srpaulo ; 322252726Srpaulo if (i < 0) 323252726Srpaulo syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m", 324252726Srpaulo pp->printer, of_pid); 325252726Srpaulo of_pid = 0; 326189251Ssam } 327252726Srpaulo (void) close(pfd); /* close printer */ 328189251Ssam if (ftruncate(lfd, pidoff) < 0) 329252726Srpaulo syslog(LOG_WARNING, "%s: ftruncate(%s): %m", 330252726Srpaulo pp->printer, pp->lock_file); 331252726Srpaulo openpr(pp); /* try to reopen printer */ 332252726Srpaulo goto restart; 333252726Srpaulo } else { 334252726Srpaulo syslog(LOG_WARNING, "%s: job could not be %s (%s)", 335252726Srpaulo pp->printer, 336281806Srpaulo pp->remote ? "sent to remote host" : "printed", 337252726Srpaulo q->job_cfname); 338252726Srpaulo if (i == REPRINT) { 339252726Srpaulo /* ensure we don't attempt this job again */ 340252726Srpaulo (void) unlink(q->job_cfname); 341252726Srpaulo q->job_cfname[0] = 'd'; 342189251Ssam (void) unlink(q->job_cfname); 343214734Srpaulo if (logname[0]) 344214734Srpaulo sendmail(pp, logname, FATALERR); 345214734Srpaulo } 346214734Srpaulo } 347214734Srpaulo } 348214734Srpaulo free(queue); 349214734Srpaulo /* 350214734Srpaulo * search the spool directory for more work. 351214734Srpaulo */ 352189251Ssam if ((nitems = getq(pp, &queue)) < 0) { 353189251Ssam syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 354214734Srpaulo pp->spool_dir); 355214734Srpaulo exit(1); 356214734Srpaulo } 357214734Srpaulo if (nitems == 0) { /* no more work to do */ 358252726Srpaulo done: 359252726Srpaulo if (jobcount > 0) { /* jobs actually printed */ 360252726Srpaulo if (!pp->no_formfeed && !pp->tof) 361252726Srpaulo (void) write(ofd, pp->form_feed, 362214734Srpaulo strlen(pp->form_feed)); 363214734Srpaulo if (pp->trailer != NULL) /* output trailer */ 364214734Srpaulo (void) write(ofd, pp->trailer, 365252726Srpaulo strlen(pp->trailer)); 366214734Srpaulo } 367214734Srpaulo (void) close(ofd); 368214734Srpaulo (void) wait(NULL); 369214734Srpaulo (void) unlink(tempstderr); 370214734Srpaulo exit(0); 371189251Ssam } 372189251Ssam goto again; 373189251Ssam} 374189251Ssam 375189251Ssamchar fonts[4][50]; /* fonts for troff */ 376189251Ssam 377189251Ssamchar ifonts[4][40] = { 378189251Ssam _PATH_VFONTR, 379189251Ssam _PATH_VFONTI, 380214734Srpaulo _PATH_VFONTB, 381189251Ssam _PATH_VFONTS, 382189251Ssam}; 383189251Ssam 384189251Ssam/* 385214734Srpaulo * The remaining part is the reading of the control file (cf) 386252726Srpaulo * and performing the various actions. 387214734Srpaulo */ 388214734Srpaulostatic int 389214734Srpauloprintit(struct printer *pp, char *file) 390189251Ssam{ 391189251Ssam register int i; 392189251Ssam char *cp; 393189251Ssam int bombed, didignorehdr; 394189251Ssam 395189251Ssam bombed = OK; 396189251Ssam didignorehdr = 0; 397189251Ssam /* 398189251Ssam * open control file; ignore if no longer there. 399189251Ssam */ 400189251Ssam if ((cfp = fopen(file, "r")) == NULL) { 401281806Srpaulo syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file); 402189251Ssam return (OK); 403189251Ssam } 404189251Ssam /* 405189251Ssam * Reset troff fonts. 406189251Ssam */ 407189251Ssam for (i = 0; i < 4; i++) 408189251Ssam strcpy(fonts[i], ifonts[i]); 409281806Srpaulo sprintf(&width[2], "%ld", pp->page_width); 410281806Srpaulo strcpy(indent+2, "0"); 411281806Srpaulo 412281806Srpaulo /* initialize job-specific count of datafiles processed */ 413281806Srpaulo job_dfcnt = 0; 414281806Srpaulo 415189251Ssam /* 416189251Ssam * read the control file for work to do 417189251Ssam * 418189251Ssam * file format -- first character in the line is a command 419189251Ssam * rest of the line is the argument. 420189251Ssam * valid commands are: 421189251Ssam * 422189251Ssam * S -- "stat info" for symbolic link protection 423189251Ssam * J -- "job name" on banner page 424189251Ssam * C -- "class name" on banner page 425189251Ssam * L -- "literal" user's name to print on banner 426189251Ssam * T -- "title" for pr 427189251Ssam * H -- "host name" of machine where lpr was done 428252726Srpaulo * P -- "person" user's login name 429252726Srpaulo * I -- "indent" amount to indent output 430189251Ssam * R -- laser dpi "resolution" 431189251Ssam * f -- "file name" name of text file to print 432189251Ssam * l -- "file name" text file with control chars 433189251Ssam * o -- "file name" postscript file, according to 434189251Ssam * the RFC. Here it is treated like an 'f'. 435189251Ssam * p -- "file name" text file to print with pr(1) 436189251Ssam * t -- "file name" troff(1) file to print 437189251Ssam * n -- "file name" ditroff(1) file to print 438189251Ssam * d -- "file name" dvi file to print 439189251Ssam * g -- "file name" plot(1G) file to print 440189251Ssam * v -- "file name" plain raster file to print 441252726Srpaulo * c -- "file name" cifplot file to print 442252726Srpaulo * 1 -- "R font file" for troff 443252726Srpaulo * 2 -- "I font file" for troff 444252726Srpaulo * 3 -- "B font file" for troff 445252726Srpaulo * 4 -- "S font file" for troff 446252726Srpaulo * N -- "name" of file (used by lpq) 447252726Srpaulo * U -- "unlink" name of file to remove 448252726Srpaulo * (after we print it. (Pass 2 only)). 449252726Srpaulo * M -- "mail" to user when done printing 450252726Srpaulo * Z -- "locale" for pr 451281806Srpaulo * 452252726Srpaulo * getline reads a line and expands tabs to blanks 453252726Srpaulo */ 454252726Srpaulo 455252726Srpaulo /* pass 1 */ 456252726Srpaulo 457281806Srpaulo while (getline(cfp)) 458252726Srpaulo switch (line[0]) { 459252726Srpaulo case 'H': 460252726Srpaulo strlcpy(origin_host, line + 1, sizeof(origin_host)); 461252726Srpaulo if (class[0] == '\0') { 462252726Srpaulo strlcpy(class, line+1, sizeof(class)); 463252726Srpaulo } 464252726Srpaulo continue; 465252726Srpaulo 466252726Srpaulo case 'P': 467252726Srpaulo strlcpy(logname, line + 1, sizeof(logname)); 468252726Srpaulo if (pp->restricted) { /* restricted */ 469252726Srpaulo if (getpwnam(logname) == NULL) { 470252726Srpaulo bombed = NOACCT; 471252726Srpaulo sendmail(pp, line+1, bombed); 472252726Srpaulo goto pass2; 473252726Srpaulo } 474281806Srpaulo } 475252726Srpaulo continue; 476252726Srpaulo 477252726Srpaulo case 'S': 478252726Srpaulo cp = line+1; 479252726Srpaulo i = 0; 480252726Srpaulo while (*cp >= '0' && *cp <= '9') 481252726Srpaulo i = i * 10 + (*cp++ - '0'); 482252726Srpaulo fdev = i; 483252726Srpaulo cp++; 484252726Srpaulo i = 0; 485252726Srpaulo while (*cp >= '0' && *cp <= '9') 486252726Srpaulo i = i * 10 + (*cp++ - '0'); 487252726Srpaulo fino = i; 488252726Srpaulo continue; 489252726Srpaulo 490252726Srpaulo case 'J': 491252726Srpaulo if (line[1] != '\0') { 492252726Srpaulo strlcpy(jobname, line + 1, sizeof(jobname)); 493189251Ssam } else 494189251Ssam strcpy(jobname, " "); 495252726Srpaulo continue; 496252726Srpaulo 497252726Srpaulo case 'C': 498252726Srpaulo if (line[1] != '\0') 499281806Srpaulo strlcpy(class, line + 1, sizeof(class)); 500281806Srpaulo else if (class[0] == '\0') { 501252726Srpaulo /* XXX - why call gethostname instead of 502189251Ssam * just strlcpy'ing local_host? */ 503189251Ssam gethostname(class, sizeof(class)); 504189251Ssam class[sizeof(class) - 1] = '\0'; 505189251Ssam } 506189251Ssam continue; 507189251Ssam 508189251Ssam case 'T': /* header title for pr */ 509189251Ssam strlcpy(title, line + 1, sizeof(title)); 510189251Ssam continue; 511252726Srpaulo 512252726Srpaulo case 'L': /* identification line */ 513252726Srpaulo if (!pp->no_header && !pp->header_last) 514252726Srpaulo banner(pp, line+1, jobname); 515252726Srpaulo continue; 516252726Srpaulo 517252726Srpaulo case '1': /* troff fonts */ 518252726Srpaulo case '2': 519252726Srpaulo case '3': 520252726Srpaulo case '4': 521252726Srpaulo if (line[1] != '\0') { 522252726Srpaulo strlcpy(fonts[line[0]-'1'], line + 1, 523189251Ssam (size_t)50); 524189251Ssam } 525189251Ssam continue; 526189251Ssam 527189251Ssam case 'W': /* page width */ 528189251Ssam strlcpy(width+2, line + 1, sizeof(width) - 2); 529189251Ssam continue; 530189251Ssam 531189251Ssam case 'I': /* indent amount */ 532189251Ssam strlcpy(indent+2, line + 1, sizeof(indent) - 2); 533189251Ssam continue; 534189251Ssam 535281806Srpaulo case 'Z': /* locale for pr */ 536281806Srpaulo strlcpy(locale, line + 1, sizeof(locale)); 537281806Srpaulo continue; 538281806Srpaulo 539281806Srpaulo default: /* some file to print */ 540281806Srpaulo /* only lowercase cmd-codes include a file-to-print */ 541281806Srpaulo if ((line[0] < 'a') || (line[0] > 'z')) { 542189251Ssam /* ignore any other lines */ 543189251Ssam if (lflag <= 1) 544252726Srpaulo continue; 545189251Ssam if (!didignorehdr) { 546189251Ssam syslog(LOG_INFO, "%s: in %s :", 547189251Ssam pp->printer, file); 548189251Ssam didignorehdr = 1; 549252726Srpaulo } 550252726Srpaulo syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 551252726Srpaulo pp->printer, line[0], &line[1]); 552252726Srpaulo continue; 553252726Srpaulo } 554252726Srpaulo i = print(pp, line[0], line+1); 555252726Srpaulo switch (i) { 556252726Srpaulo case ERROR: 557252726Srpaulo if (bombed == OK) 558252726Srpaulo bombed = FATALERR; 559252726Srpaulo break; 560252726Srpaulo case REPRINT: 561252726Srpaulo (void) fclose(cfp); 562252726Srpaulo return (REPRINT); 563252726Srpaulo case FILTERERR: 564189251Ssam case ACCESS: 565189251Ssam bombed = i; 566189251Ssam sendmail(pp, logname, bombed); 567189251Ssam } 568189251Ssam title[0] = '\0'; 569189251Ssam continue; 570189251Ssam 571189251Ssam case 'N': 572189251Ssam case 'U': 573189251Ssam case 'M': 574252726Srpaulo case 'R': 575252726Srpaulo continue; 576189251Ssam } 577189251Ssam 578189251Ssam /* pass 2 */ 579189251Ssam 580189251Ssampass2: 581189251Ssam fseek(cfp, 0L, 0); 582189251Ssam while (getline(cfp)) 583189251Ssam switch (line[0]) { 584189251Ssam case 'L': /* identification line */ 585281806Srpaulo if (!pp->no_header && pp->header_last) 586281806Srpaulo banner(pp, line+1, jobname); 587281806Srpaulo continue; 588281806Srpaulo 589281806Srpaulo case 'M': 590281806Srpaulo if (bombed < NOACCT) /* already sent if >= NOACCT */ 591281806Srpaulo sendmail(pp, line+1, bombed); 592189251Ssam continue; 593189251Ssam 594281806Srpaulo case 'U': 595281806Srpaulo if (strchr(line+1, '/')) 596281806Srpaulo continue; 597281806Srpaulo (void) unlink(line+1); 598281806Srpaulo } 599281806Srpaulo /* 600281806Srpaulo * clean-up in case another control file exists 601281806Srpaulo */ 602281806Srpaulo (void) fclose(cfp); 603281806Srpaulo (void) unlink(file); 604281806Srpaulo return (bombed == OK ? OK : ERROR); 605281806Srpaulo} 606281806Srpaulo 607281806Srpaulo/* 608281806Srpaulo * Print a file. 609281806Srpaulo * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 610281806Srpaulo * Return -1 if a non-recoverable error occured, 611281806Srpaulo * 2 if the filter detected some errors (but printed the job anyway), 612281806Srpaulo * 1 if we should try to reprint this job and 613281806Srpaulo * 0 if all is well. 614281806Srpaulo * Note: all filters take stdin as the file, stdout as the printer, 615281806Srpaulo * stderr as the log file, and must not ignore SIGINT. 616281806Srpaulo */ 617281806Srpaulostatic int 618281806Srpauloprint(struct printer *pp, int format, char *file) 619281806Srpaulo{ 620281806Srpaulo register int n, i; 621281806Srpaulo register char *prog; 622281806Srpaulo int fi, fo; 623281806Srpaulo FILE *fp; 624281806Srpaulo char *av[15], buf[SPL_BUFSIZ]; 625281806Srpaulo pid_t wpid; 626281806Srpaulo int p[2], retcode, stopped, wstatus, wstatus_set; 627281806Srpaulo struct stat stb; 628281806Srpaulo 629281806Srpaulo /* Make sure the entire data file has arrived. */ 630281806Srpaulo wait4data(pp, file); 631281806Srpaulo 632281806Srpaulo if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 633281806Srpaulo syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 634281806Srpaulo pp->printer, file, format); 635281806Srpaulo return (ERROR); 636281806Srpaulo } 637281806Srpaulo /* 638281806Srpaulo * Check to see if data file is a symbolic link. If so, it should 639281806Srpaulo * still point to the same file or someone is trying to print 640281806Srpaulo * something he shouldn't. 641281806Srpaulo */ 642281806Srpaulo if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 643281806Srpaulo (stb.st_dev != fdev || stb.st_ino != fino)) 644281806Srpaulo return (ACCESS); 645281806Srpaulo 646281806Srpaulo job_dfcnt++; /* increment datafile counter for this job */ 647281806Srpaulo stopped = 0; /* output filter is not stopped */ 648281806Srpaulo 649281806Srpaulo /* everything seems OK, start it up */ 650281806Srpaulo if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 651281806Srpaulo (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 652281806Srpaulo pp->tof = 1; 653189251Ssam } 654189251Ssam if (pp->filters[LPF_INPUT] == NULL 655281806Srpaulo && (format == 'f' || format == 'l' || format == 'o')) { 656281806Srpaulo pp->tof = 0; 657281806Srpaulo while ((n = read(fi, buf, SPL_BUFSIZ)) > 0) 658281806Srpaulo if (write(ofd, buf, n) != n) { 659189251Ssam (void) close(fi); 660189251Ssam return (REPRINT); 661281806Srpaulo } 662281806Srpaulo (void) close(fi); 663281806Srpaulo return (OK); 664281806Srpaulo } 665189251Ssam switch (format) { 666281806Srpaulo case 'p': /* print file using 'pr' */ 667252726Srpaulo if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 668252726Srpaulo prog = _PATH_PR; 669252726Srpaulo i = 0; 670252726Srpaulo av[i++] = "pr"; 671252726Srpaulo av[i++] = width; 672252726Srpaulo av[i++] = length; 673189251Ssam av[i++] = "-h"; 674189251Ssam av[i++] = *title ? title : " "; 675189251Ssam av[i++] = "-L"; 676189251Ssam av[i++] = *locale ? locale : "C"; 677189251Ssam av[i++] = "-F"; 678189251Ssam av[i] = 0; 679189251Ssam fo = ofd; 680189251Ssam goto start; 681189251Ssam } 682189251Ssam pipe(p); 683189251Ssam if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 684189251Ssam dup2(fi, STDIN_FILENO); /* file is stdin */ 685189251Ssam dup2(p[1], STDOUT_FILENO); /* pipe is stdout */ 686189251Ssam closelog(); 687189251Ssam closeallfds(3); 688189251Ssam execl(_PATH_PR, "pr", width, length, 689189251Ssam "-h", *title ? title : " ", 690189251Ssam "-L", *locale ? locale : "C", 691189251Ssam "-F", (char *)0); 692281806Srpaulo syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 693281806Srpaulo exit(2); 694281806Srpaulo } 695281806Srpaulo (void) close(p[1]); /* close output side */ 696281806Srpaulo (void) close(fi); 697281806Srpaulo if (prchild < 0) { 698189251Ssam prchild = 0; 699189251Ssam (void) close(p[0]); 700189251Ssam return (ERROR); 701252726Srpaulo } 702252726Srpaulo fi = p[0]; /* use pipe for input */ 703189251Ssam case 'f': /* print plain text file */ 704189251Ssam prog = pp->filters[LPF_INPUT]; 705252726Srpaulo av[1] = width; 706252726Srpaulo av[2] = length; 707252726Srpaulo av[3] = indent; 708189251Ssam n = 4; 709189251Ssam break; 710189251Ssam case 'o': /* print postscript file */ 711252726Srpaulo /* 712252726Srpaulo * Treat this as a "plain file with control characters", and 713189251Ssam * assume the standard LPF_INPUT filter will recognize that 714252726Srpaulo * the data is postscript and know what to do with it. These 715252726Srpaulo * 'o'-file requests could come from MacOS 10.1 systems. 716252726Srpaulo * (later versions of MacOS 10 will explicitly use 'l') 717252726Srpaulo * A postscript file can contain binary data, which is why 'l' 718252726Srpaulo * is somewhat more appropriate than 'f'. 719252726Srpaulo */ 720252726Srpaulo /* FALLTHROUGH */ 721252726Srpaulo case 'l': /* like 'f' but pass control characters */ 722252726Srpaulo prog = pp->filters[LPF_INPUT]; 723252726Srpaulo av[1] = "-c"; 724252726Srpaulo av[2] = width; 725252726Srpaulo av[3] = length; 726252726Srpaulo av[4] = indent; 727252726Srpaulo n = 5; 728252726Srpaulo break; 729252726Srpaulo case 'r': /* print a fortran text file */ 730252726Srpaulo prog = pp->filters[LPF_FORTRAN]; 731252726Srpaulo av[1] = width; 732252726Srpaulo av[2] = length; 733252726Srpaulo n = 3; 734189251Ssam break; 735189251Ssam case 't': /* print troff output */ 736189251Ssam case 'n': /* print ditroff output */ 737252726Srpaulo case 'd': /* print tex output */ 738252726Srpaulo (void) unlink(".railmag"); 739252726Srpaulo if ((fo = creat(".railmag", FILMOD)) < 0) { 740252726Srpaulo syslog(LOG_ERR, "%s: cannot create .railmag", 741281806Srpaulo pp->printer); 742252726Srpaulo (void) unlink(".railmag"); 743189251Ssam } else { 744189251Ssam for (n = 0; n < 4; n++) { 745189251Ssam if (fonts[n][0] != '/') 746189251Ssam (void) write(fo, _PATH_VFONT, 747189251Ssam sizeof(_PATH_VFONT) - 1); 748189251Ssam (void) write(fo, fonts[n], strlen(fonts[n])); 749189251Ssam (void) write(fo, "\n", 1); 750189251Ssam } 751189251Ssam (void) close(fo); 752252726Srpaulo } 753252726Srpaulo prog = (format == 't') ? pp->filters[LPF_TROFF] 754189251Ssam : ((format == 'n') ? pp->filters[LPF_DITROFF] 755252726Srpaulo : pp->filters[LPF_DVI]); 756252726Srpaulo av[1] = pxwidth; 757252726Srpaulo av[2] = pxlength; 758252726Srpaulo n = 3; 759252726Srpaulo break; 760252726Srpaulo case 'c': /* print cifplot output */ 761252726Srpaulo prog = pp->filters[LPF_CIFPLOT]; 762252726Srpaulo av[1] = pxwidth; 763252726Srpaulo av[2] = pxlength; 764252726Srpaulo n = 3; 765252726Srpaulo break; 766252726Srpaulo case 'g': /* print plot(1G) output */ 767252726Srpaulo prog = pp->filters[LPF_GRAPH]; 768252726Srpaulo av[1] = pxwidth; 769252726Srpaulo av[2] = pxlength; 770252726Srpaulo n = 3; 771252726Srpaulo break; 772252726Srpaulo case 'v': /* print raster output */ 773252726Srpaulo prog = pp->filters[LPF_RASTER]; 774252726Srpaulo av[1] = pxwidth; 775189251Ssam av[2] = pxlength; 776189251Ssam n = 3; 777189251Ssam break; 778252726Srpaulo default: 779189251Ssam (void) close(fi); 780189251Ssam syslog(LOG_ERR, "%s: illegal format character '%c'", 781189251Ssam pp->printer, format); 782252726Srpaulo return (ERROR); 783252726Srpaulo } 784189251Ssam if (prog == NULL) { 785252726Srpaulo (void) close(fi); 786252726Srpaulo syslog(LOG_ERR, 787189251Ssam "%s: no filter found in printcap for format character '%c'", 788252726Srpaulo pp->printer, format); 789252726Srpaulo return (ERROR); 790252726Srpaulo } 791252726Srpaulo if ((av[0] = strrchr(prog, '/')) != NULL) 792252726Srpaulo av[0]++; 793252726Srpaulo else 794252726Srpaulo av[0] = prog; 795252726Srpaulo av[n++] = "-n"; 796252726Srpaulo av[n++] = logname; 797252726Srpaulo av[n++] = "-h"; 798252726Srpaulo av[n++] = origin_host; 799252726Srpaulo av[n++] = pp->acct_file; 800252726Srpaulo av[n] = 0; 801252726Srpaulo fo = pfd; 802252726Srpaulo if (of_pid > 0) { /* stop output filter */ 803252726Srpaulo write(ofd, "\031\1", 2); 804281806Srpaulo while ((wpid = 805281806Srpaulo wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid) 806281806Srpaulo ; 807281806Srpaulo if (wpid < 0) 808281806Srpaulo syslog(LOG_WARNING, 809281806Srpaulo "%s: after stopping 'of', wait3() returned: %m", 810281806Srpaulo pp->printer); 811252726Srpaulo else if (!WIFSTOPPED(wstatus)) { 812252726Srpaulo (void) close(fi); 813252726Srpaulo syslog(LOG_WARNING, "%s: output filter died " 814252726Srpaulo "(pid=%d retcode=%d termsig=%d)", 815252726Srpaulo pp->printer, of_pid, WEXITSTATUS(wstatus), 816252726Srpaulo WTERMSIG(wstatus)); 817252726Srpaulo return (REPRINT); 818252726Srpaulo } 819252726Srpaulo stopped++; 820252726Srpaulo } 821252726Srpaulostart: 822252726Srpaulo if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 823252726Srpaulo dup2(fi, STDIN_FILENO); 824252726Srpaulo dup2(fo, STDOUT_FILENO); 825189251Ssam /* setup stderr for the filter (child process) 826252726Srpaulo * so it goes to our temporary errors file */ 827252726Srpaulo n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 828189251Ssam if (n >= 0) 829189251Ssam dup2(n, STDERR_FILENO); 830189251Ssam closelog(); 831252726Srpaulo closeallfds(3); 832252726Srpaulo execv(prog, av); 833252726Srpaulo syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, 834189251Ssam prog); 835252726Srpaulo exit(2); 836252726Srpaulo } 837252726Srpaulo (void) close(fi); 838252726Srpaulo wstatus_set = 0; 839252726Srpaulo if (child < 0) 840252726Srpaulo retcode = 100; 841189251Ssam else { 842189251Ssam while ((wpid = wait(&wstatus)) > 0 && wpid != child) 843189251Ssam ; 844252726Srpaulo if (wpid < 0) { 845252726Srpaulo retcode = 100; 846189251Ssam syslog(LOG_WARNING, 847252726Srpaulo "%s: after execv(%s), wait() returned: %m", 848252726Srpaulo pp->printer, prog); 849189251Ssam } else { 850189251Ssam wstatus_set = 1; 851252726Srpaulo retcode = WEXITSTATUS(wstatus); 852252726Srpaulo } 853252726Srpaulo } 854252726Srpaulo child = 0; 855189251Ssam prchild = 0; 856189251Ssam if (stopped) { /* restart output filter */ 857189251Ssam if (kill(of_pid, SIGCONT) < 0) { 858281806Srpaulo syslog(LOG_ERR, "cannot restart output filter"); 859252726Srpaulo exit(1); 860189251Ssam } 861281806Srpaulo } 862189251Ssam pp->tof = 0; 863189251Ssam 864252726Srpaulo /* Copy the filter's output to "lf" logfile */ 865214734Srpaulo if ((fp = fopen(tempstderr, "r"))) { 866252726Srpaulo while (fgets(buf, sizeof(buf), fp)) 867189251Ssam fputs(buf, stderr); 868189251Ssam fclose(fp); 869189251Ssam } 870189251Ssam 871189251Ssam if (wstatus_set && !WIFEXITED(wstatus)) { 872214734Srpaulo syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 873214734Srpaulo pp->printer, format, WTERMSIG(wstatus)); 874214734Srpaulo return (ERROR); 875252726Srpaulo } 876214734Srpaulo switch (retcode) { 877214734Srpaulo case 0: 878214734Srpaulo pp->tof = 1; 879214734Srpaulo return (OK); 880214734Srpaulo case 1: 881214734Srpaulo return (REPRINT); 882214734Srpaulo case 2: 883214734Srpaulo return (ERROR); 884214734Srpaulo default: 885214734Srpaulo syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 886214734Srpaulo pp->printer, format, retcode); 887214734Srpaulo return (FILTERERR); 888252726Srpaulo } 889252726Srpaulo} 890252726Srpaulo 891252726Srpaulo/* 892252726Srpaulo * Send the daemon control file (cf) and any data files. 893252726Srpaulo * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 894252726Srpaulo * 0 if all is well. 895214734Srpaulo */ 896214734Srpaulostatic int 897214734Srpaulosendit(struct printer *pp, char *file) 898214734Srpaulo{ 899214734Srpaulo int dfcopies, err, i; 900214734Srpaulo char *cp, last[sizeof(line)]; 901214734Srpaulo 902189251Ssam /* 903252726Srpaulo * open control file 904189251Ssam */ 905214734Srpaulo if ((cfp = fopen(file, "r")) == NULL) 906214734Srpaulo return (OK); 907252726Srpaulo 908214734Srpaulo /* initialize job-specific count of datafiles processed */ 909214734Srpaulo job_dfcnt = 0; 910214734Srpaulo 911214734Srpaulo /* 912214734Srpaulo * read the control file for work to do 913189251Ssam * 914189251Ssam * file format -- first character in the line is a command 915189251Ssam * rest of the line is the argument. 916281806Srpaulo * commands of interest are: 917189251Ssam * 918189251Ssam * a-z -- "file name" name of file to print 919189251Ssam * U -- "unlink" name of file to remove 920189251Ssam * (after we print it. (Pass 2 only)). 921189251Ssam */ 922189251Ssam 923189251Ssam /* 924252726Srpaulo * pass 1 925252726Srpaulo */ 926252726Srpaulo err = OK; 927252726Srpaulo while (getline(cfp)) { 928252726Srpaulo again: 929252726Srpaulo if (line[0] == 'S') { 930252726Srpaulo cp = line+1; 931214734Srpaulo i = 0; 932214734Srpaulo while (*cp >= '0' && *cp <= '9') 933214734Srpaulo i = i * 10 + (*cp++ - '0'); 934252726Srpaulo fdev = i; 935214734Srpaulo cp++; 936214734Srpaulo i = 0; 937214734Srpaulo while (*cp >= '0' && *cp <= '9') 938214734Srpaulo i = i * 10 + (*cp++ - '0'); 939214734Srpaulo fino = i; 940214734Srpaulo } else if (line[0] == 'H') { 941214734Srpaulo strlcpy(origin_host, line + 1, sizeof(origin_host)); 942214734Srpaulo if (class[0] == '\0') { 943214734Srpaulo strlcpy(class, line + 1, sizeof(class)); 944214734Srpaulo } 945214734Srpaulo } else if (line[0] == 'P') { 946214734Srpaulo strlcpy(logname, line + 1, sizeof(logname)); 947214734Srpaulo if (pp->restricted) { /* restricted */ 948214734Srpaulo if (getpwnam(logname) == NULL) { 949252726Srpaulo sendmail(pp, line+1, NOACCT); 950252726Srpaulo err = ERROR; 951252726Srpaulo break; 952214734Srpaulo } 953252726Srpaulo } 954252726Srpaulo } else if (line[0] == 'I') { 955214734Srpaulo strlcpy(indent+2, line + 1, sizeof(indent) - 2); 956214734Srpaulo } else if (line[0] >= 'a' && line[0] <= 'z') { 957214734Srpaulo dfcopies = 1; 958252726Srpaulo strcpy(last, line); 959214734Srpaulo while ((i = getline(cfp)) != 0) { 960214734Srpaulo if (strcmp(last, line) != 0) 961214734Srpaulo break; 962214734Srpaulo dfcopies++; 963214734Srpaulo } 964214734Srpaulo switch (sendfile(pp, '\3', last+1, *last, dfcopies)) { 965252726Srpaulo case OK: 966214734Srpaulo if (i) 967214734Srpaulo goto again; 968214734Srpaulo break; 969214734Srpaulo case REPRINT: 970214734Srpaulo (void) fclose(cfp); 971214734Srpaulo return (REPRINT); 972214734Srpaulo case ACCESS: 973214734Srpaulo sendmail(pp, logname, ACCESS); 974214734Srpaulo case ERROR: 975214734Srpaulo err = ERROR; 976214734Srpaulo } 977214734Srpaulo break; 978214734Srpaulo } 979252726Srpaulo } 980252726Srpaulo if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) { 981252726Srpaulo (void) fclose(cfp); 982252726Srpaulo return (REPRINT); 983252726Srpaulo } 984252726Srpaulo /* 985252726Srpaulo * pass 2 986252726Srpaulo */ 987252726Srpaulo fseek(cfp, 0L, 0); 988252726Srpaulo while (getline(cfp)) 989252726Srpaulo if (line[0] == 'U' && !strchr(line+1, '/')) 990252726Srpaulo (void) unlink(line+1); 991214734Srpaulo /* 992214734Srpaulo * clean-up in case another control file exists 993252726Srpaulo */ 994252726Srpaulo (void) fclose(cfp); 995214734Srpaulo (void) unlink(file); 996214734Srpaulo return (err); 997214734Srpaulo} 998252726Srpaulo 999252726Srpaulo/* 1000214734Srpaulo * Send a data file to the remote machine and spool it. 1001214734Srpaulo * Return positive if we should try resending. 1002214734Srpaulo */ 1003214734Srpaulostatic int 1004252726Srpaulosendfile(struct printer *pp, int type, char *file, char format, int copyreq) 1005252726Srpaulo{ 1006252726Srpaulo int i, amt; 1007252726Srpaulo struct stat stb; 1008252726Srpaulo char *av[15], *filtcmd; 1009252726Srpaulo char buf[SPL_BUFSIZ], opt_c[4], opt_h[4], opt_n[4]; 1010252726Srpaulo int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc; 1011252726Srpaulo 1012252726Srpaulo /* Make sure the entire data file has arrived. */ 1013252726Srpaulo wait4data(pp, file); 1014252726Srpaulo 1015252726Srpaulo statrc = lstat(file, &stb); 1016252726Srpaulo if (statrc < 0) { 1017252726Srpaulo syslog(LOG_ERR, "%s: error from lstat(%s): %m", 1018252726Srpaulo pp->printer, file); 1019252726Srpaulo return (ERROR); 1020252726Srpaulo } 1021252726Srpaulo sfd = open(file, O_RDONLY); 1022252726Srpaulo if (sfd < 0) { 1023252726Srpaulo syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 1024252726Srpaulo pp->printer, file); 1025252726Srpaulo return (ERROR); 1026252726Srpaulo } 1027252726Srpaulo /* 1028252726Srpaulo * Check to see if data file is a symbolic link. If so, it should 1029252726Srpaulo * still point to the same file or someone is trying to print something 1030252726Srpaulo * he shouldn't. 1031252726Srpaulo */ 1032252726Srpaulo if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 && 1033252726Srpaulo (stb.st_dev != fdev || stb.st_ino != fino)) { 1034252726Srpaulo close(sfd); 1035252726Srpaulo return (ACCESS); 1036252726Srpaulo } 1037252726Srpaulo 1038214734Srpaulo /* Everything seems OK for reading the file, now to send it */ 1039214734Srpaulo filtcmd = NULL; 1040214734Srpaulo sizerr = 0; 1041281806Srpaulo tfd = -1; 1042252726Srpaulo if (type == '\3') { 1043214734Srpaulo /* 1044214734Srpaulo * Type == 3 means this is a datafile, not a control file. 1045214734Srpaulo * Increment the counter of data-files in this job, and 1046214734Srpaulo * then check for input or output filters (which are only 1047214734Srpaulo * applied to datafiles, not control files). 1048214734Srpaulo */ 1049252726Srpaulo job_dfcnt++; 1050252726Srpaulo 1051252726Srpaulo /* 1052189251Ssam * Note that here we are filtering datafiles, one at a time, 1053252726Srpaulo * as they are sent to the remote machine. Here, the *only* 1054252726Srpaulo * difference between an input filter (`if=') and an output 1055252726Srpaulo * filter (`of=') is the argument list that the filter is 1056252726Srpaulo * started up with. Here, the output filter is executed 1057252726Srpaulo * for each individual file as it is sent. This is not the 1058189251Ssam * same as local print queues, where the output filter is 1059189251Ssam * started up once, and then all jobs are passed thru that 1060252726Srpaulo * single invocation of the output filter. 1061252726Srpaulo * 1062189251Ssam * Also note that a queue for a remote-machine can have an 1063252726Srpaulo * input filter or an output filter, but not both. 1064189251Ssam */ 1065189251Ssam if (pp->filters[LPF_INPUT]) { 1066252726Srpaulo filtcmd = pp->filters[LPF_INPUT]; 1067252726Srpaulo av[0] = filtcmd; 1068252726Srpaulo narg = 0; 1069252726Srpaulo strcpy(opt_c, "-c"); 1070252726Srpaulo strcpy(opt_h, "-h"); 1071252726Srpaulo strcpy(opt_n, "-n"); 1072252726Srpaulo if (format == 'l') 1073252726Srpaulo av[++narg] = opt_c; 1074252726Srpaulo av[++narg] = width; 1075252726Srpaulo av[++narg] = length; 1076252726Srpaulo av[++narg] = indent; 1077252726Srpaulo av[++narg] = opt_n; 1078189251Ssam av[++narg] = logname; 1079189251Ssam av[++narg] = opt_h; 1080189251Ssam av[++narg] = origin_host; 1081189251Ssam av[++narg] = pp->acct_file; 1082189251Ssam av[++narg] = NULL; 1083189251Ssam } else if (pp->filters[LPF_OUTPUT]) { 1084189251Ssam filtcmd = pp->filters[LPF_OUTPUT]; 1085189251Ssam av[0] = filtcmd; 1086189251Ssam narg = 0; 1087189251Ssam av[++narg] = width; 1088189251Ssam av[++narg] = length; 1089189251Ssam av[++narg] = NULL; 1090189251Ssam } 1091189251Ssam } 1092189251Ssam if (filtcmd) { 1093281806Srpaulo /* 1094189251Ssam * If there is an input or output filter, we have to run 1095189251Ssam * the datafile thru that filter and store the result as 1096189251Ssam * a temporary spool file, because the protocol requires 1097189251Ssam * that we send the remote host the file-size before we 1098189251Ssam * start to send any of the data. 1099189251Ssam */ 1100281806Srpaulo strcpy(tfile, TFILENAME); 1101189251Ssam tfd = mkstemp(tfile); 1102189251Ssam if (tfd == -1) { 1103189251Ssam syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 1104189251Ssam TFILENAME); 1105189251Ssam sfres = ERROR; 1106189251Ssam goto return_sfres; 1107189251Ssam } 1108189251Ssam filtstat = execfilter(pp, filtcmd, av, sfd, tfd); 1109189251Ssam 1110189251Ssam /* process the return-code from the filter */ 1111189251Ssam switch (filtstat) { 1112189251Ssam case 0: 1113189251Ssam break; 1114189251Ssam case 1: 1115189251Ssam sfres = REPRINT; 1116189251Ssam goto return_sfres; 1117189251Ssam case 2: 1118189251Ssam sfres = ERROR; 1119189251Ssam goto return_sfres; 1120189251Ssam default: 1121189251Ssam syslog(LOG_WARNING, 1122189251Ssam "%s: filter '%c' exited (retcode=%d)", 1123189251Ssam pp->printer, format, filtstat); 1124189251Ssam sfres = FILTERERR; 1125189251Ssam goto return_sfres; 1126281806Srpaulo } 1127189251Ssam statrc = fstat(tfd, &stb); /* to find size of tfile */ 1128189251Ssam if (statrc < 0) { 1129189251Ssam syslog(LOG_ERR, 1130189251Ssam "%s: error processing 'if', fstat(%s): %m", 1131189251Ssam pp->printer, tfile); 1132189251Ssam sfres = ERROR; 1133281806Srpaulo goto return_sfres; 1134189251Ssam } 1135189251Ssam close(sfd); 1136189251Ssam sfd = tfd; 1137189251Ssam lseek(sfd, 0, SEEK_SET); 1138189251Ssam } 1139189251Ssam 1140189251Ssam copycnt = 0; 1141189251Ssamsendagain: 1142189251Ssam copycnt++; 1143189251Ssam 1144189251Ssam if (copycnt < 2) 1145189251Ssam (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1146189251Ssam else 1147189251Ssam (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size, 1148189251Ssam file, copycnt); 1149189251Ssam amt = strlen(buf); 1150189251Ssam for (i = 0; ; i++) { 1151189251Ssam if (write(pfd, buf, amt) != amt || 1152189251Ssam (resp = response(pp)) < 0 || resp == '\1') { 1153189251Ssam sfres = REPRINT; 1154189251Ssam goto return_sfres; 1155189251Ssam } else if (resp == '\0') 1156189251Ssam break; 1157189251Ssam if (i == 0) 1158189251Ssam pstatus(pp, 1159189251Ssam "no space on remote; waiting for queue to drain"); 1160281806Srpaulo if (i == 10) 1161189251Ssam syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1162189251Ssam pp->printer, pp->remote_host); 1163189251Ssam sleep(5 * 60); 1164189251Ssam } 1165189251Ssam if (i) 1166189251Ssam pstatus(pp, "sending to %s", pp->remote_host); 1167281806Srpaulo /* 1168189251Ssam * XXX - we should change trstat_init()/trstat_write() to include 1169189251Ssam * the copycnt in the statistics record it may write. 1170189251Ssam */ 1171189251Ssam if (type == '\3') 1172189251Ssam trstat_init(pp, file, job_dfcnt); 1173189251Ssam for (i = 0; i < stb.st_size; i += SPL_BUFSIZ) { 1174189251Ssam amt = SPL_BUFSIZ; 1175189251Ssam if (i + amt > stb.st_size) 1176189251Ssam amt = stb.st_size - i; 1177189251Ssam if (sizerr == 0 && read(sfd, buf, amt) != amt) 1178189251Ssam sizerr = 1; 1179189251Ssam if (write(pfd, buf, amt) != amt) { 1180189251Ssam sfres = REPRINT; 1181189251Ssam goto return_sfres; 1182189251Ssam } 1183189251Ssam } 1184189251Ssam 1185189251Ssam if (sizerr) { 1186189251Ssam syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1187189251Ssam /* tell recvjob to ignore this file */ 1188189251Ssam (void) write(pfd, "\1", 1); 1189189251Ssam sfres = ERROR; 1190189251Ssam goto return_sfres; 1191189251Ssam } 1192189251Ssam if (write(pfd, "", 1) != 1 || response(pp)) { 1193281806Srpaulo sfres = REPRINT; 1194189251Ssam goto return_sfres; 1195189251Ssam } 1196189251Ssam if (type == '\3') { 1197189251Ssam trstat_write(pp, TR_SENDING, stb.st_size, logname, 1198189251Ssam pp->remote_host, origin_host); 1199189251Ssam /* 1200281806Srpaulo * Usually we only need to send one copy of a datafile, 1201189251Ssam * because the control-file will simply print the same 1202189251Ssam * file multiple times. However, some printers ignore 1203189251Ssam * the control file, and simply print each data file as 1204189251Ssam * it arrives. For such "remote hosts", we need to 1205189251Ssam * transfer the same data file multiple times. Such a 1206189251Ssam * a host is indicated by adding 'rc' to the printcap 1207189251Ssam * entry. 1208189251Ssam * XXX - Right now this ONLY works for remote hosts which 1209189251Ssam * do ignore the name of the data file, because 1210189251Ssam * this sends the file multiple times with slight 1211189251Ssam * changes to the filename. To do this right would 1212189251Ssam * require that we also rewrite the control file 1213189251Ssam * to match those filenames. 1214189251Ssam */ 1215189251Ssam if (pp->resend_copies && (copycnt < copyreq)) { 1216189251Ssam lseek(sfd, 0, SEEK_SET); 1217189251Ssam goto sendagain; 1218189251Ssam } 1219189251Ssam } 1220189251Ssam sfres = OK; 1221189251Ssam 1222189251Ssamreturn_sfres: 1223189251Ssam (void)close(sfd); 1224189251Ssam if (tfd != -1) { 1225281806Srpaulo /* 1226189251Ssam * If tfd is set, then it is the same value as sfd, and 1227189251Ssam * therefore it is already closed at this point. All 1228189251Ssam * we need to do is remove the temporary file. 1229189251Ssam */ 1230189251Ssam tfd = -1; 1231189251Ssam unlink(tfile); 1232281806Srpaulo } 1233189251Ssam return (sfres); 1234189251Ssam} 1235189251Ssam 1236189251Ssam/* 1237189251Ssam * Some print servers send the control-file first, and then start sending the 1238189251Ssam * matching data file(s). That is not the correct order. If some queue is 1239189251Ssam * already printing an active job, then when that job is finished the queue 1240189251Ssam * may proceed to the control file of any incoming print job. This turns 1241189251Ssam * into a race between the process which is receiving the data file, and the 1242189251Ssam * process which is actively printing the very same file. When the remote 1243281806Srpaulo * server sends files in the wrong order, it is even possible that a queue 1244281806Srpaulo * will start to print a data file before the file has been created! 1245281806Srpaulo * 1246281806Srpaulo * So before we start to print() or send() a data file, we call this routine 1247281806Srpaulo * to make sure the data file is not still changing in size. Note that this 1248281806Srpaulo * problem will only happen for jobs arriving from a remote host, and that 1249281806Srpaulo * the process which has decided to print this job (and is thus making this 1250281806Srpaulo * check) is *not* the process which is receiving the job. 1251281806Srpaulo * 1252281806Srpaulo * A second benefit of this is that any incoming job is guaranteed to appear 1253281806Srpaulo * in a queue listing for at least a few seconds after it has arrived. Some 1254281806Srpaulo * lpr implementations get confused if they send a job and it disappears 1255281806Srpaulo * from the queue before they can check on it. 1256281806Srpaulo */ 1257281806Srpaulo#define MAXWAIT_ARRIVE 16 /* max to wait for the file to *exist* */ 1258281806Srpaulo#define MAXWAIT_4DATA (20*60) /* max to wait for it to stop changing */ 1259281806Srpaulo#define MINWAIT_4DATA 4 /* This value must be >= 1 */ 1260281806Srpaulo#define DEBUG_MINWAIT 1 1261281806Srpaulostatic void 1262281806Srpaulowait4data(struct printer *pp, const char *dfile) 1263281806Srpaulo{ 1264281806Srpaulo const char *cp; 1265281806Srpaulo int statres; 1266281806Srpaulo u_int sleepreq; 1267281806Srpaulo size_t dlen, hlen; 1268281806Srpaulo time_t amtslept, cur_time, prev_mtime; 1269281806Srpaulo struct stat statdf; 1270281806Srpaulo 1271281806Srpaulo /* Skip these checks if the print job is from the local host. */ 1272281806Srpaulo dlen = strlen(dfile); 1273281806Srpaulo hlen = strlen(local_host); 1274281806Srpaulo if (dlen > hlen) { 1275189251Ssam cp = dfile + dlen - hlen; 1276189251Ssam if (strcmp(cp, local_host) == 0) 1277189251Ssam return; 1278189251Ssam } 1279189251Ssam 1280189251Ssam /* 1281189251Ssam * If this data file does not exist, then wait up to MAXWAIT_ARRIVE 1282189251Ssam * seconds for it to arrive. 1283189251Ssam */ 1284189251Ssam amtslept = 0; 1285189251Ssam statres = stat(dfile, &statdf); 1286189251Ssam while (statres < 0 && amtslept < MAXWAIT_ARRIVE) { 1287189251Ssam if (amtslept == 0) 1288189251Ssam pstatus(pp, "Waiting for data file from remote host"); 1289189251Ssam amtslept += MINWAIT_4DATA - sleep(MINWAIT_4DATA); 1290189251Ssam statres = stat(dfile, &statdf); 1291281806Srpaulo } 1292189251Ssam if (statres < 0) { 1293189251Ssam /* The file still does not exist, so just give up on it. */ 1294189251Ssam syslog(LOG_WARNING, "%s: wait4data() abandoned wait for %s", 1295189251Ssam pp->printer, dfile); 1296189251Ssam return; 1297189251Ssam } 1298281806Srpaulo 1299189251Ssam /* 1300189251Ssam * The file exists, so keep waiting until the data file has not 1301189251Ssam * changed for some reasonable amount of time. Extra care is 1302189251Ssam * taken when computing wait-times, just in case there are data 1303189251Ssam * files with a last-modify time in the future. While that is 1304189251Ssam * very unlikely to happen, it can happen when the system has 1305189251Ssam * a flakey time-of-day clock. 1306189251Ssam */ 1307189251Ssam prev_mtime = statdf.st_mtime; 1308189251Ssam cur_time = time(NULL); 1309189251Ssam if (statdf.st_mtime >= cur_time - MINWAIT_4DATA) { 1310189251Ssam if (statdf.st_mtime >= cur_time) /* some TOD oddity */ 1311189251Ssam sleepreq = MINWAIT_4DATA; 1312189251Ssam else 1313189251Ssam sleepreq = cur_time - statdf.st_mtime; 1314189251Ssam if (amtslept == 0) 1315189251Ssam pstatus(pp, "Waiting for data file from remote host"); 1316189251Ssam amtslept += sleepreq - sleep(sleepreq); 1317252726Srpaulo statres = stat(dfile, &statdf); 1318252726Srpaulo } 1319189251Ssam sleepreq = MINWAIT_4DATA; 1320252726Srpaulo while (statres == 0 && amtslept < MAXWAIT_4DATA) { 1321252726Srpaulo if (statdf.st_mtime == prev_mtime) 1322252726Srpaulo break; 1323252726Srpaulo prev_mtime = statdf.st_mtime; 1324189251Ssam amtslept += sleepreq - sleep(sleepreq); 1325189251Ssam statres = stat(dfile, &statdf); 1326189251Ssam } 1327252726Srpaulo 1328252726Srpaulo if (statres != 0) 1329252726Srpaulo syslog(LOG_WARNING, "%s: %s disappeared during wait4data()", 1330252726Srpaulo pp->printer, dfile); 1331252726Srpaulo else if (amtslept > MAXWAIT_4DATA) 1332252726Srpaulo syslog(LOG_WARNING, 1333189251Ssam "%s: %s still changing after %lu secs in wait4data()", 1334189251Ssam pp->printer, dfile, (unsigned long)amtslept); 1335189251Ssam#if DEBUG_MINWAIT 1336189251Ssam else if (amtslept > MINWAIT_4DATA) 1337189251Ssam syslog(LOG_INFO, "%s: slept %lu secs in wait4data(%s)", 1338189251Ssam pp->printer, (unsigned long)amtslept, dfile); 1339189251Ssam#endif 1340189251Ssam} 1341189251Ssam#undef MAXWAIT_ARRIVE 1342189251Ssam#undef MAXWAIT_4DATA 1343252726Srpaulo#undef MINWAIT_4DATA 1344189251Ssam 1345189251Ssam/* 1346189251Ssam * This routine is called to execute one of the filters as was 1347189251Ssam * specified in a printcap entry. While the child-process will read 1348189251Ssam * all of 'infd', it is up to the caller to close that file descriptor 1349189251Ssam * in the parent process. 1350252726Srpaulo */ 1351189251Ssamstatic int 1352189251Ssamexecfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd) 1353189251Ssam{ 1354189251Ssam pid_t fpid, wpid; 1355189251Ssam int errfd, retcode, wstatus; 1356189251Ssam FILE *errfp; 1357252726Srpaulo char buf[BUFSIZ], *slash; 1358189251Ssam 1359189251Ssam fpid = dofork(pp, DORETURN); 1360189251Ssam if (fpid != 0) { 1361189251Ssam /* 1362189251Ssam * This is the parent process, which just waits for the child 1363189251Ssam * to complete and then returns the result. Note that it is 1364189251Ssam * the child process which reads the input stream. 1365189251Ssam */ 1366189251Ssam if (fpid < 0) 1367189251Ssam retcode = 100; 1368189251Ssam else { 1369189251Ssam while ((wpid = wait(&wstatus)) > 0 && 1370189251Ssam wpid != fpid) 1371252726Srpaulo ; 1372189251Ssam if (wpid < 0) { 1373189251Ssam retcode = 100; 1374189251Ssam syslog(LOG_WARNING, 1375189251Ssam "%s: after execv(%s), wait() returned: %m", 1376189251Ssam pp->printer, f_cmd); 1377189251Ssam } else 1378189251Ssam retcode = WEXITSTATUS(wstatus); 1379189251Ssam } 1380189251Ssam 1381189251Ssam /* 1382189251Ssam * Copy everything the filter wrote to stderr from our 1383189251Ssam * temporary errors file to the "lf=" logfile. 1384189251Ssam */ 1385189251Ssam errfp = fopen(tempstderr, "r"); 1386189251Ssam if (errfp) { 1387189251Ssam while (fgets(buf, sizeof(buf), errfp)) 1388189251Ssam fputs(buf, stderr); 1389189251Ssam fclose(errfp); 1390189251Ssam } 1391189251Ssam 1392189251Ssam return (retcode); 1393189251Ssam } 1394189251Ssam 1395189251Ssam /* 1396189251Ssam * This is the child process, which is the one that executes the 1397189251Ssam * given filter. 1398189251Ssam */ 1399189251Ssam /* 1400189251Ssam * If the first parameter has any slashes in it, then change it 1401189251Ssam * to point to the first character after the last slash. 1402189251Ssam */ 1403189251Ssam slash = strrchr(f_av[0], '/'); 1404252726Srpaulo if (slash != NULL) 1405189251Ssam f_av[0] = slash + 1; 1406189251Ssam /* 1407189251Ssam * XXX - in the future, this should setup an explicit list of 1408189251Ssam * environment variables and use execve()! 1409189251Ssam */ 1410252726Srpaulo 1411189251Ssam /* 1412189251Ssam * Setup stdin, stdout, and stderr as we want them when the filter 1413189251Ssam * is running. Stderr is setup so it points to a temporary errors 1414189251Ssam * file, and the parent process will copy that temporary file to 1415189251Ssam * the real logfile after the filter completes. 1416189251Ssam */ 1417189251Ssam dup2(infd, STDIN_FILENO); 1418189251Ssam dup2(outfd, STDOUT_FILENO); 1419189251Ssam errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1420189251Ssam if (errfd >= 0) 1421189251Ssam dup2(errfd, STDERR_FILENO); 1422189251Ssam closelog(); 1423189251Ssam closeallfds(3); 1424189251Ssam execv(f_cmd, f_av); 1425189251Ssam syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd); 1426189251Ssam exit(2); 1427189251Ssam /* NOTREACHED */ 1428252726Srpaulo} 1429252726Srpaulo 1430252726Srpaulo/* 1431252726Srpaulo * Check to make sure there have been no errors and that both programs 1432281806Srpaulo * are in sync with eachother. 1433281806Srpaulo * Return non-zero if the connection was lost. 1434281806Srpaulo */ 1435281806Srpaulostatic char 1436281806Srpauloresponse(const struct printer *pp) 1437281806Srpaulo{ 1438281806Srpaulo char resp; 1439281806Srpaulo 1440281806Srpaulo if (read(pfd, &resp, 1) != 1) { 1441281806Srpaulo syslog(LOG_INFO, "%s: lost connection", pp->printer); 1442281806Srpaulo return (-1); 1443281806Srpaulo } 1444281806Srpaulo return (resp); 1445281806Srpaulo} 1446281806Srpaulo 1447281806Srpaulo/* 1448281806Srpaulo * Banner printing stuff 1449281806Srpaulo */ 1450252726Srpaulostatic void 1451252726Srpaulobanner(struct printer *pp, char *name1, char *name2) 1452252726Srpaulo{ 1453252726Srpaulo time_t tvec; 1454252726Srpaulo 1455252726Srpaulo time(&tvec); 1456252726Srpaulo if (!pp->no_formfeed && !pp->tof) 1457252726Srpaulo (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1458252726Srpaulo if (pp->short_banner) { /* short banner only */ 1459252726Srpaulo if (class[0]) { 1460252726Srpaulo (void) write(ofd, class, strlen(class)); 1461252726Srpaulo (void) write(ofd, ":", 1); 1462252726Srpaulo } 1463252726Srpaulo (void) write(ofd, name1, strlen(name1)); 1464252726Srpaulo (void) write(ofd, " Job: ", 7); 1465252726Srpaulo (void) write(ofd, name2, strlen(name2)); 1466252726Srpaulo (void) write(ofd, " Date: ", 8); 1467252726Srpaulo (void) write(ofd, ctime(&tvec), 24); 1468252726Srpaulo (void) write(ofd, "\n", 1); 1469252726Srpaulo } else { /* normal banner */ 1470252726Srpaulo (void) write(ofd, "\n\n\n", 3); 1471252726Srpaulo scan_out(pp, ofd, name1, '\0'); 1472252726Srpaulo (void) write(ofd, "\n\n", 2); 1473252726Srpaulo scan_out(pp, ofd, name2, '\0'); 1474252726Srpaulo if (class[0]) { 1475189251Ssam (void) write(ofd,"\n\n\n",3); 1476189251Ssam scan_out(pp, ofd, class, '\0'); 1477252726Srpaulo } 1478252726Srpaulo (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1479189251Ssam (void) write(ofd, name2, strlen(name2)); 1480189251Ssam (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1481189251Ssam (void) write(ofd, ctime(&tvec), 24); 1482281806Srpaulo (void) write(ofd, "\n", 1); 1483281806Srpaulo } 1484281806Srpaulo if (!pp->no_formfeed) 1485281806Srpaulo (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1486281806Srpaulo pp->tof = 1; 1487281806Srpaulo} 1488281806Srpaulo 1489281806Srpaulostatic char * 1490281806Srpauloscnline(int key, char *p, int c) 1491281806Srpaulo{ 1492281806Srpaulo register int scnwidth; 1493281806Srpaulo 1494189251Ssam for (scnwidth = WIDTH; --scnwidth;) { 1495189251Ssam key <<= 1; 1496189251Ssam *p++ = key & 0200 ? c : BACKGND; 1497189251Ssam } 1498189251Ssam return (p); 1499189251Ssam} 1500189251Ssam 1501189251Ssam#define TRC(q) (((q)-' ')&0177) 1502189251Ssam 1503189251Ssamstatic void 1504189251Ssamscan_out(struct printer *pp, int scfd, char *scsp, int dlm) 1505189251Ssam{ 1506189251Ssam register char *strp; 1507189251Ssam register int nchrs, j; 1508189251Ssam char outbuf[LINELEN+1], *sp, c, cc; 1509189251Ssam int d, scnhgt; 1510189251Ssam 1511189251Ssam for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1512189251Ssam strp = &outbuf[0]; 1513189251Ssam sp = scsp; 1514189251Ssam for (nchrs = 0; ; ) { 1515189251Ssam d = dropit(c = TRC(cc = *sp++)); 1516189251Ssam if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1517281806Srpaulo for (j = WIDTH; --j;) 1518189251Ssam *strp++ = BACKGND; 1519189251Ssam else 1520189251Ssam strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1521189251Ssam if (*sp == dlm || *sp == '\0' || 1522189251Ssam nchrs++ >= pp->page_width/(WIDTH+1)-1) 1523189251Ssam break; 1524189251Ssam *strp++ = BACKGND; 1525189251Ssam *strp++ = BACKGND; 1526189251Ssam } 1527189251Ssam while (*--strp == BACKGND && strp >= outbuf) 1528189251Ssam ; 1529189251Ssam strp++; 1530252726Srpaulo *strp++ = '\n'; 1531252726Srpaulo (void) write(scfd, outbuf, strp-outbuf); 1532189251Ssam } 1533252726Srpaulo} 1534252726Srpaulo 1535252726Srpaulostatic int 1536252726Srpaulodropit(int c) 1537252726Srpaulo{ 1538252726Srpaulo switch(c) { 1539252726Srpaulo 1540252726Srpaulo case TRC('_'): 1541252726Srpaulo case TRC(';'): 1542252726Srpaulo case TRC(','): 1543189251Ssam case TRC('g'): 1544189251Ssam case TRC('j'): 1545252726Srpaulo case TRC('p'): 1546189251Ssam case TRC('q'): 1547189251Ssam case TRC('y'): 1548189251Ssam return (DROP); 1549189251Ssam 1550189251Ssam default: 1551189251Ssam return (0); 1552189251Ssam } 1553189251Ssam} 1554189251Ssam 1555189251Ssam/* 1556189251Ssam * sendmail --- 1557189251Ssam * tell people about job completion 1558189251Ssam */ 1559189251Ssamstatic void 1560189251Ssamsendmail(struct printer *pp, char *userid, int bombed) 1561189251Ssam{ 1562189251Ssam register int i; 1563189251Ssam int p[2], s; 1564252726Srpaulo register const char *cp; 1565189251Ssam struct stat stb; 1566189251Ssam FILE *fp; 1567189251Ssam 1568189251Ssam pipe(p); 1569189251Ssam if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1570189251Ssam dup2(p[0], STDIN_FILENO); 1571189251Ssam closelog(); 1572189251Ssam closeallfds(3); 1573189251Ssam if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1574189251Ssam cp++; 1575189251Ssam else 1576189251Ssam cp = _PATH_SENDMAIL; 1577189251Ssam execl(_PATH_SENDMAIL, cp, "-t", (char *)0); 1578189251Ssam _exit(0); 1579189251Ssam } else if (s > 0) { /* parent */ 1580189251Ssam dup2(p[1], STDOUT_FILENO); 1581189251Ssam printf("To: %s@%s\n", userid, origin_host); 1582189251Ssam printf("Subject: %s printer job \"%s\"\n", pp->printer, 1583189251Ssam *jobname ? jobname : "<unknown>"); 1584189251Ssam printf("Reply-To: root@%s\n\n", local_host); 1585281806Srpaulo printf("Your printer job "); 1586281806Srpaulo if (*jobname) 1587281806Srpaulo printf("(%s) ", jobname); 1588281806Srpaulo 1589189251Ssam switch (bombed) { 1590281806Srpaulo case OK: 1591189251Ssam cp = "OK"; 1592189251Ssam printf("\ncompleted successfully\n"); 1593189251Ssam break; 1594189251Ssam default: 1595189251Ssam case FATALERR: 1596189251Ssam cp = "FATALERR"; 1597189251Ssam printf("\ncould not be printed\n"); 1598189251Ssam break; 1599189251Ssam case NOACCT: 1600189251Ssam cp = "NOACCT"; 1601189251Ssam printf("\ncould not be printed without an account on %s\n", 1602189251Ssam local_host); 1603189251Ssam break; 1604189251Ssam case FILTERERR: 1605189251Ssam cp = "FILTERERR"; 1606189251Ssam if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1607189251Ssam || (fp = fopen(tempstderr, "r")) == NULL) { 1608189251Ssam printf("\nhad some errors and may not have printed\n"); 1609189251Ssam break; 1610189251Ssam } 1611189251Ssam printf("\nhad the following errors and may not have printed:\n"); 1612189251Ssam while ((i = getc(fp)) != EOF) 1613189251Ssam putchar(i); 1614189251Ssam (void) fclose(fp); 1615189251Ssam break; 1616189251Ssam case ACCESS: 1617189251Ssam cp = "ACCESS"; 1618189251Ssam printf("\nwas not printed because it was not linked to the original file\n"); 1619189251Ssam } 1620189251Ssam fflush(stdout); 1621189251Ssam (void) close(STDOUT_FILENO); 1622189251Ssam } else { 1623189251Ssam syslog(LOG_WARNING, "unable to send mail to %s: %m", userid); 1624189251Ssam return; 1625189251Ssam } 1626189251Ssam (void) close(p[0]); 1627189251Ssam (void) close(p[1]); 1628189251Ssam wait(NULL); 1629189251Ssam syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1630189251Ssam userid, *jobname ? jobname : "<unknown>", pp->printer, cp); 1631189251Ssam} 1632189251Ssam 1633189251Ssam/* 1634189251Ssam * dofork - fork with retries on failure 1635189251Ssam */ 1636189251Ssamstatic int 1637189251Ssamdofork(const struct printer *pp, int action) 1638281806Srpaulo{ 1639189251Ssam pid_t forkpid; 1640189251Ssam int i, fail; 1641189251Ssam struct passwd *pwd; 1642189251Ssam 1643189251Ssam forkpid = -1; 1644189251Ssam if (daemon_uname == NULL) { 1645189251Ssam pwd = getpwuid(pp->daemon_user); 1646189251Ssam if (pwd == NULL) { 1647189251Ssam syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file", 1648252726Srpaulo pp->printer, pp->daemon_user); 1649189251Ssam goto error_ret; 1650189251Ssam } 1651189251Ssam daemon_uname = strdup(pwd->pw_name); 1652189251Ssam daemon_defgid = pwd->pw_gid; 1653189251Ssam } 1654189251Ssam 1655189251Ssam for (i = 0; i < 20; i++) { 1656189251Ssam forkpid = fork(); 1657189251Ssam if (forkpid < 0) { 1658189251Ssam sleep((unsigned)(i*i)); 1659214734Srpaulo continue; 1660214734Srpaulo } 1661214734Srpaulo /* 1662252726Srpaulo * Child should run as daemon instead of root 1663214734Srpaulo */ 1664214734Srpaulo if (forkpid == 0) { 1665214734Srpaulo errno = 0; 1666214734Srpaulo fail = initgroups(daemon_uname, daemon_defgid); 1667214734Srpaulo if (fail) { 1668214734Srpaulo syslog(LOG_ERR, "%s: initgroups(%s,%u): %m", 1669214734Srpaulo pp->printer, daemon_uname, daemon_defgid); 1670214734Srpaulo break; 1671214734Srpaulo } 1672214734Srpaulo fail = setgid(daemon_defgid); 1673214734Srpaulo if (fail) { 1674214734Srpaulo syslog(LOG_ERR, "%s: setgid(%u): %m", 1675214734Srpaulo pp->printer, daemon_defgid); 1676214734Srpaulo break; 1677214734Srpaulo } 1678252726Srpaulo fail = setuid(pp->daemon_user); 1679214734Srpaulo if (fail) { 1680214734Srpaulo syslog(LOG_ERR, "%s: setuid(%ld): %m", 1681214734Srpaulo pp->printer, pp->daemon_user); 1682214734Srpaulo break; 1683214734Srpaulo } 1684214734Srpaulo } 1685214734Srpaulo return (forkpid); 1686214734Srpaulo } 1687214734Srpaulo 1688214734Srpaulo /* 1689252726Srpaulo * An error occurred. If the error is in the child process, then 1690214734Srpaulo * this routine MUST always exit(). DORETURN only effects how 1691214734Srpaulo * errors should be handled in the parent process. 1692214734Srpaulo */ 1693214734Srpauloerror_ret: 1694214734Srpaulo if (forkpid == 0) { 1695214734Srpaulo syslog(LOG_ERR, "%s: dofork(): aborting child process...", 1696214734Srpaulo pp->printer); 1697214734Srpaulo exit(1); 1698214734Srpaulo } 1699214734Srpaulo syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer); 1700214734Srpaulo 1701214734Srpaulo sleep(1); /* throttle errors, as a safety measure */ 1702214734Srpaulo switch (action) { 1703214734Srpaulo case DORETURN: 1704214734Srpaulo return (-1); 1705214734Srpaulo default: 1706214734Srpaulo syslog(LOG_ERR, "bad action (%d) to dofork", action); 1707214734Srpaulo /* FALLTHROUGH */ 1708214734Srpaulo case DOABORT: 1709214734Srpaulo exit(1); 1710214734Srpaulo } 1711214734Srpaulo /*NOTREACHED*/ 1712214734Srpaulo} 1713214734Srpaulo 1714252726Srpaulo/* 1715252726Srpaulo * Kill child processes to abort current job. 1716252726Srpaulo */ 1717252726Srpaulostatic void 1718252726Srpauloabortpr(int signo __unused) 1719252726Srpaulo{ 1720252726Srpaulo 1721252726Srpaulo (void) unlink(tempstderr); 1722252726Srpaulo kill(0, SIGINT); 1723252726Srpaulo if (of_pid > 0) 1724252726Srpaulo kill(of_pid, SIGCONT); 1725252726Srpaulo while (wait(NULL) > 0) 1726252726Srpaulo ; 1727252726Srpaulo if (of_pid > 0 && tfd != -1) 1728281806Srpaulo unlink(tfile); 1729281806Srpaulo exit(0); 1730281806Srpaulo} 1731281806Srpaulo 1732281806Srpaulostatic void 1733281806Srpauloinit(struct printer *pp) 1734281806Srpaulo{ 1735214734Srpaulo char *s; 1736214734Srpaulo 1737214734Srpaulo sprintf(&width[2], "%ld", pp->page_width); 1738214734Srpaulo sprintf(&length[2], "%ld", pp->page_length); 1739214734Srpaulo sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1740214734Srpaulo sprintf(&pxlength[2], "%ld", pp->page_plength); 1741214734Srpaulo if ((s = checkremote(pp)) != 0) { 1742214734Srpaulo syslog(LOG_WARNING, "%s", s); 1743214734Srpaulo free(s); 1744214734Srpaulo } 1745214734Srpaulo} 1746214734Srpaulo 1747214734Srpaulovoid 1748214734Srpaulostartprinting(const char *printer) 1749214734Srpaulo{ 1750281806Srpaulo struct printer myprinter, *pp = &myprinter; 1751214734Srpaulo int status; 1752214734Srpaulo 1753214734Srpaulo init_printer(pp); 1754214734Srpaulo status = getprintcap(printer, pp); 1755281806Srpaulo switch(status) { 1756214734Srpaulo case PCAPERR_OSERR: 1757214734Srpaulo syslog(LOG_ERR, "can't open printer description file: %m"); 1758214734Srpaulo exit(1); 1759214734Srpaulo case PCAPERR_NOTFOUND: 1760252726Srpaulo syslog(LOG_ERR, "unknown printer: %s", printer); 1761252726Srpaulo exit(1); 1762252726Srpaulo case PCAPERR_TCLOOP: 1763252726Srpaulo fatal(pp, "potential reference loop detected in printcap file"); 1764281806Srpaulo default: 1765281806Srpaulo break; 1766281806Srpaulo } 1767281806Srpaulo printjob(pp); 1768281806Srpaulo} 1769281806Srpaulo 1770281806Srpaulo/* 1771281806Srpaulo * Acquire line printer or remote connection. 1772281806Srpaulo */ 1773281806Srpaulostatic void 1774281806Srpauloopenpr(const struct printer *pp) 1775281806Srpaulo{ 1776281806Srpaulo int p[2]; 1777281806Srpaulo char *cp; 1778281806Srpaulo 1779281806Srpaulo if (pp->remote) { 1780281806Srpaulo openrem(pp); 1781281806Srpaulo /* 1782281806Srpaulo * Lpd does support the setting of 'of=' filters for 1783281806Srpaulo * jobs going to remote machines, but that does not 1784281806Srpaulo * have the same meaning as 'of=' does when handling 1785281806Srpaulo * local print queues. For remote machines, all 'of=' 1786281806Srpaulo * filter processing is handled in sendfile(), and that 1787281806Srpaulo * does not use these global "output filter" variables. 1788281806Srpaulo */ 1789252726Srpaulo ofd = -1; 1790252726Srpaulo of_pid = 0; 1791252726Srpaulo return; 1792252726Srpaulo } else if (*pp->lp) { 1793252726Srpaulo if ((cp = strchr(pp->lp, '@')) != NULL) 1794252726Srpaulo opennet(pp); 1795252726Srpaulo else 1796252726Srpaulo opentty(pp); 1797252726Srpaulo } else { 1798252726Srpaulo syslog(LOG_ERR, "%s: no line printer device or host name", 1799252726Srpaulo pp->printer); 1800252726Srpaulo exit(1); 1801252726Srpaulo } 1802252726Srpaulo 1803252726Srpaulo /* 1804252726Srpaulo * Start up an output filter, if needed. 1805252726Srpaulo */ 1806252726Srpaulo if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) { 1807252726Srpaulo pipe(p); 1808252726Srpaulo if (pp->remote) { 1809252726Srpaulo strcpy(tfile, TFILENAME); 1810252726Srpaulo tfd = mkstemp(tfile); 1811252726Srpaulo } 1812252726Srpaulo if ((of_pid = dofork(pp, DOABORT)) == 0) { /* child */ 1813252726Srpaulo dup2(p[0], STDIN_FILENO); /* pipe is std in */ 1814252726Srpaulo /* tfile/printer is stdout */ 1815252726Srpaulo dup2(pp->remote ? tfd : pfd, STDOUT_FILENO); 1816252726Srpaulo closelog(); 1817252726Srpaulo closeallfds(3); 1818252726Srpaulo if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1819252726Srpaulo cp = pp->filters[LPF_OUTPUT]; 1820252726Srpaulo else 1821252726Srpaulo cp++; 1822252726Srpaulo execl(pp->filters[LPF_OUTPUT], cp, width, length, 1823252726Srpaulo (char *)0); 1824252726Srpaulo syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer, 1825252726Srpaulo pp->filters[LPF_OUTPUT]); 1826252726Srpaulo exit(1); 1827252726Srpaulo } 1828252726Srpaulo (void) close(p[0]); /* close input side */ 1829252726Srpaulo ofd = p[1]; /* use pipe for output */ 1830252726Srpaulo } else { 1831252726Srpaulo ofd = pfd; 1832252726Srpaulo of_pid = 0; 1833281806Srpaulo } 1834281806Srpaulo} 1835281806Srpaulo 1836281806Srpaulo/* 1837281806Srpaulo * Printer connected directly to the network 1838281806Srpaulo * or to a terminal server on the net 1839281806Srpaulo */ 1840281806Srpaulostatic void 1841281806Srpauloopennet(const struct printer *pp) 1842281806Srpaulo{ 1843281806Srpaulo register int i; 1844281806Srpaulo int resp; 1845281806Srpaulo u_long port; 1846281806Srpaulo char *ep; 1847252726Srpaulo void (*savealrm)(int); 1848252726Srpaulo 1849252726Srpaulo port = strtoul(pp->lp, &ep, 0); 1850252726Srpaulo if (*ep != '@' || port > 65535) { 1851252726Srpaulo syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1852252726Srpaulo pp->lp); 1853252726Srpaulo exit(1); 1854252726Srpaulo } 1855252726Srpaulo ep++; 1856252726Srpaulo 1857252726Srpaulo for (i = 1; ; i = i < 256 ? i << 1 : i) { 1858252726Srpaulo resp = -1; 1859252726Srpaulo savealrm = signal(SIGALRM, alarmhandler); 1860252726Srpaulo alarm(pp->conn_timeout); 1861252726Srpaulo pfd = getport(pp, ep, port); 1862252726Srpaulo alarm(0); 1863252726Srpaulo (void)signal(SIGALRM, savealrm); 1864252726Srpaulo if (pfd < 0 && errno == ECONNREFUSED) 1865252726Srpaulo resp = 1; 1866252726Srpaulo else if (pfd >= 0) { 1867252726Srpaulo /* 1868252726Srpaulo * need to delay a bit for rs232 lines 1869252726Srpaulo * to stabilize in case printer is 1870252726Srpaulo * connected via a terminal server 1871252726Srpaulo */ 1872252726Srpaulo delay(500); 1873252726Srpaulo break; 1874252726Srpaulo } 1875252726Srpaulo if (i == 1) { 1876252726Srpaulo if (resp < 0) 1877252726Srpaulo pstatus(pp, "waiting for %s to come up", 1878252726Srpaulo pp->lp); 1879252726Srpaulo else 1880252726Srpaulo pstatus(pp, 1881252726Srpaulo "waiting for access to printer on %s", 1882252726Srpaulo pp->lp); 1883252726Srpaulo } 1884252726Srpaulo sleep(i); 1885252726Srpaulo } 1886252726Srpaulo pstatus(pp, "sending to %s port %lu", ep, port); 1887252726Srpaulo} 1888252726Srpaulo 1889252726Srpaulo/* 1890252726Srpaulo * Printer is connected to an RS232 port on this host 1891252726Srpaulo */ 1892252726Srpaulostatic void 1893252726Srpauloopentty(const struct printer *pp) 1894252726Srpaulo{ 1895252726Srpaulo register int i; 1896252726Srpaulo 1897252726Srpaulo for (i = 1; ; i = i < 32 ? i << 1 : i) { 1898252726Srpaulo pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1899252726Srpaulo if (pfd >= 0) { 1900252726Srpaulo delay(500); 1901252726Srpaulo break; 1902252726Srpaulo } 1903252726Srpaulo if (errno == ENOENT) { 1904252726Srpaulo syslog(LOG_ERR, "%s: %m", pp->lp); 1905252726Srpaulo exit(1); 1906252726Srpaulo } 1907252726Srpaulo if (i == 1) 1908252726Srpaulo pstatus(pp, 1909252726Srpaulo "waiting for %s to become ready (offline?)", 1910252726Srpaulo pp->printer); 1911252726Srpaulo sleep(i); 1912252726Srpaulo } 1913252726Srpaulo if (isatty(pfd)) 1914252726Srpaulo setty(pp); 1915252726Srpaulo pstatus(pp, "%s is ready and printing", pp->printer); 1916252726Srpaulo} 1917252726Srpaulo 1918252726Srpaulo/* 1919252726Srpaulo * Printer is on a remote host 1920252726Srpaulo */ 1921252726Srpaulostatic void 1922252726Srpauloopenrem(const struct printer *pp) 1923252726Srpaulo{ 1924252726Srpaulo register int i; 1925252726Srpaulo int resp; 1926252726Srpaulo void (*savealrm)(int); 1927252726Srpaulo 1928252726Srpaulo for (i = 1; ; i = i < 256 ? i << 1 : i) { 1929252726Srpaulo resp = -1; 1930252726Srpaulo savealrm = signal(SIGALRM, alarmhandler); 1931281806Srpaulo alarm(pp->conn_timeout); 1932252726Srpaulo pfd = getport(pp, pp->remote_host, 0); 1933281806Srpaulo alarm(0); 1934252726Srpaulo (void)signal(SIGALRM, savealrm); 1935252726Srpaulo if (pfd >= 0) { 1936252726Srpaulo if ((writel(pfd, "\2", pp->remote_queue, "\n", 1937252726Srpaulo (char *)0) 1938252726Srpaulo == 2 + strlen(pp->remote_queue)) 1939252726Srpaulo && (resp = response(pp)) == 0) 1940252726Srpaulo break; 1941252726Srpaulo (void) close(pfd); 1942252726Srpaulo } 1943252726Srpaulo if (i == 1) { 1944252726Srpaulo if (resp < 0) 1945252726Srpaulo pstatus(pp, "waiting for %s to come up", 1946252726Srpaulo pp->remote_host); 1947252726Srpaulo else { 1948252726Srpaulo pstatus(pp, 1949252726Srpaulo "waiting for queue to be enabled on %s", 1950252726Srpaulo pp->remote_host); 1951252726Srpaulo i = 256; 1952252726Srpaulo } 1953252726Srpaulo } 1954214734Srpaulo sleep(i); 1955214734Srpaulo } 1956252726Srpaulo pstatus(pp, "sending to %s", pp->remote_host); 1957252726Srpaulo} 1958252726Srpaulo 1959252726Srpaulo/* 1960252726Srpaulo * setup tty lines. 1961252726Srpaulo */ 1962252726Srpaulostatic void 1963252726Srpaulosetty(const struct printer *pp) 1964281806Srpaulo{ 1965252726Srpaulo struct termios ttybuf; 1966252726Srpaulo 1967252726Srpaulo if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1968252726Srpaulo syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1969252726Srpaulo exit(1); 1970252726Srpaulo } 1971252726Srpaulo if (tcgetattr(pfd, &ttybuf) < 0) { 1972252726Srpaulo syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1973252726Srpaulo exit(1); 1974252726Srpaulo } 1975252726Srpaulo if (pp->baud_rate > 0) 1976252726Srpaulo cfsetspeed(&ttybuf, pp->baud_rate); 1977252726Srpaulo if (pp->mode_set) { 1978252726Srpaulo char *s = strdup(pp->mode_set), *tmp; 1979252726Srpaulo 1980252726Srpaulo while ((tmp = strsep(&s, ",")) != NULL) { 1981252726Srpaulo (void) msearch(tmp, &ttybuf); 1982252726Srpaulo } 1983252726Srpaulo } 1984252726Srpaulo if (pp->mode_set != 0 || pp->baud_rate > 0) { 1985252726Srpaulo if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1986252726Srpaulo syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1987252726Srpaulo } 1988252726Srpaulo } 1989252726Srpaulo} 1990252726Srpaulo 1991252726Srpaulo#include <stdarg.h> 1992252726Srpaulo 1993252726Srpaulostatic void 1994252726Srpaulopstatus(const struct printer *pp, const char *msg, ...) 1995281806Srpaulo{ 1996281806Srpaulo int fd; 1997281806Srpaulo char *buf; 1998281806Srpaulo va_list ap; 1999252726Srpaulo va_start(ap, msg); 2000281806Srpaulo 2001281806Srpaulo umask(S_IWOTH); 2002281806Srpaulo fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 2003281806Srpaulo if (fd < 0) { 2004281806Srpaulo syslog(LOG_ERR, "%s: open(%s): %m", pp->printer, 2005281806Srpaulo pp->status_file); 2006281806Srpaulo exit(1); 2007281806Srpaulo } 2008281806Srpaulo ftruncate(fd, 0); 2009252726Srpaulo vasprintf(&buf, msg, ap); 2010252726Srpaulo va_end(ap); 2011252726Srpaulo writel(fd, buf, "\n", (char *)0); 2012252726Srpaulo close(fd); 2013281806Srpaulo free(buf); 2014252726Srpaulo} 2015252726Srpaulo 2016252726Srpaulovoid 2017252726Srpauloalarmhandler(int signo __unused) 2018252726Srpaulo{ 2019252726Srpaulo /* the signal is ignored */ 2020252726Srpaulo /* (the '__unused' is just to avoid a compile-time warning) */ 2021252726Srpaulo} 2022252726Srpaulo