printjob.c revision 79735
155714Skris/* 255714Skris * Copyright (c) 1983, 1993 355714Skris * The Regents of the University of California. All rights reserved. 455714Skris * 555714Skris * 655714Skris * Redistribution and use in source and binary forms, with or without 755714Skris * modification, are permitted provided that the following conditions 855714Skris * are met: 955714Skris * 1. Redistributions of source code must retain the above copyright 1055714Skris * notice, this list of conditions and the following disclaimer. 1155714Skris * 2. Redistributions in binary form must reproduce the above copyright 1255714Skris * notice, this list of conditions and the following disclaimer in the 1355714Skris * documentation and/or other materials provided with the distribution. 1455714Skris * 3. All advertising materials mentioning features or use of this software 1555714Skris * must display the following acknowledgement: 1655714Skris * This product includes software developed by the University of 1755714Skris * California, Berkeley and its contributors. 1855714Skris * 4. Neither the name of the University nor the names of its contributors 1955714Skris * may be used to endorse or promote products derived from this software 2055714Skris * without specific prior written permission. 2155714Skris * 2255714Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2355714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2455714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2555714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2655714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2755714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2855714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2955714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3055714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3155714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3255714Skris * SUCH DAMAGE. 3355714Skris */ 3455714Skris 3555714Skris#ifndef lint 3655714Skrisstatic const char copyright[] = 3755714Skris"@(#) Copyright (c) 1983, 1993\n\ 3855714Skris The Regents of the University of California. All rights reserved.\n"; 3955714Skris#endif /* not lint */ 4055714Skris 4155714Skris#ifndef lint 4255714Skris/* 4355714Skrisstatic char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 4455714Skris*/ 4555714Skrisstatic const char rcsid[] = 4655714Skris "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 79735 2001-07-14 21:49:17Z gad $"; 4755714Skris#endif /* not lint */ 4855714Skris 4955714Skris 5055714Skris/* 5155714Skris * printjob -- print jobs in the queue. 5255714Skris * 5355714Skris * NOTE: the lock file is used to pass information to lpq and lprm. 5455714Skris * it does not need to be removed because file locks are dynamic. 5555714Skris */ 5655714Skris 5755714Skris#include <sys/param.h> 5855714Skris#include <sys/wait.h> 59109998Smarkm#include <sys/stat.h> 6059191Skris#include <sys/types.h> 6155714Skris 6255714Skris#include <pwd.h> 6355714Skris#include <unistd.h> 6455714Skris#include <signal.h> 6555714Skris#include <syslog.h> 6655714Skris#include <fcntl.h> 6755714Skris#include <dirent.h> 6855714Skris#include <errno.h> 6955714Skris#include <stdio.h> 7055714Skris#include <string.h> 7155714Skris#include <stdlib.h> 7255714Skris#include <sys/ioctl.h> 7355714Skris#include <termios.h> 7455714Skris#include <time.h> 7555714Skris#include "lp.h" 7659191Skris#include "lp.local.h" 7755714Skris#include "pathnames.h" 7855714Skris#include "extern.h" 7955714Skris 8055714Skris#define DORETURN 0 /* absorb fork error */ 8155714Skris#define DOABORT 1 /* abort if dofork fails */ 8255714Skris 8355714Skris/* 8455714Skris * Error tokens 8555714Skris */ 8655714Skris#define REPRINT -2 8759191Skris#define ERROR -1 8859191Skris#define OK 0 8959191Skris#define FATALERR 1 9059191Skris#define NOACCT 2 9155714Skris#define FILTERERR 3 9255714Skris#define ACCESS 4 93109998Smarkm 9455714Skrisstatic dev_t fdev; /* device of file pointed to by symlink */ 9555714Skrisstatic ino_t fino; /* inode of file pointed to by symlink */ 9655714Skrisstatic FILE *cfp; /* control file */ 9755714Skrisstatic int child; /* id of any filters */ 9855714Skrisstatic int job_dfcnt; /* count of datafiles in current user job */ 9955714Skrisstatic int lfd; /* lock file descriptor */ 10059191Skrisstatic int ofd; /* output filter file descriptor */ 101109998Smarkmstatic int ofilter; /* id of output filter, if any */ 10255714Skrisstatic int tfd = -1; /* output filter temp file output */ 10355714Skrisstatic int pfd; /* prstatic inter file descriptor */ 10455714Skrisstatic int pid; /* pid of lpd process */ 10555714Skrisstatic int prchild; /* id of pr process */ 10655714Skrisstatic char title[80]; /* ``pr'' title */ 10755714Skrisstatic char locale[80]; /* ``pr'' locale */ 10855714Skris 109109998Smarkmstatic char class[32]; /* classification field */ 110109998Smarkmstatic char origin_host[MAXHOSTNAMELEN]; /* user's host machine */ 111109998Smarkm /* indentation size in static characters */ 11255714Skrisstatic char indent[10] = "-i0"; 11355714Skrisstatic char jobname[100]; /* job or file name */ 11455714Skrisstatic char length[10] = "-l"; /* page length in lines */ 11555714Skrisstatic char logname[32]; /* user's login name */ 11655714Skrisstatic char pxlength[10] = "-y"; /* page length in pixels */ 11755714Skrisstatic char pxwidth[10] = "-x"; /* page width in pixels */ 11855714Skris/* tempstderr is the filename used to catch stderr from exec-ing filters */ 11955714Skrisstatic char tempstderr[] = "errs.XXXXXXX"; 12055714Skrisstatic char width[10] = "-w"; /* page width in static characters */ 12155714Skris#define TFILENAME "fltXXXXXX" 12255714Skrisstatic char tfile[] = TFILENAME; /* file name for filter output */ 12355714Skris 12455714Skrisstatic void abortpr(int _signo); 12555714Skrisstatic void alarmhandler(int _signo); 12655714Skrisstatic void banner(struct printer *_pp, char *_name1, char *_name2); 12755714Skrisstatic int dofork(const struct printer *_pp, int _action); 12855714Skrisstatic int dropit(int _c); 12955714Skrisstatic void init(struct printer *_pp); 13055714Skrisstatic void openpr(const struct printer *_pp); 13155714Skrisstatic void opennet(const struct printer *_pp); 13255714Skrisstatic void opentty(const struct printer *_pp); 13355714Skrisstatic void openrem(const struct printer *pp); 13455714Skrisstatic int print(struct printer *_pp, int _format, char *_file); 13555714Skrisstatic int printit(struct printer *_pp, char *_file); 13655714Skrisstatic void pstatus(const struct printer *_pp, const char *_msg, ...); 13755714Skrisstatic char response(const struct printer *_pp); 13855714Skrisstatic void scan_out(struct printer *_pp, int _scfd, char *_scsp, 13955714Skris int _dlm); 14055714Skrisstatic char *scnline(int _key, char *_p, int _c); 14155714Skrisstatic int sendfile(struct printer *_pp, int _type, char *_file, 142109998Smarkm char _format); 143109998Smarkmstatic int sendit(struct printer *_pp, char *_file); 144109998Smarkmstatic void sendmail(struct printer *_pp, char *_user, int _bombed); 145109998Smarkmstatic void setty(const struct printer *_pp); 146109998Smarkm 14755714Skrisvoid 14855714Skrisprintjob(struct printer *pp) 14955714Skris{ 15055714Skris struct stat stb; 15155714Skris register struct jobqueue *q, **qp; 15259191Skris struct jobqueue **queue; 15355714Skris register int i, nitems; 15459191Skris off_t pidoff; 15559191Skris int errcnt, jobcount, tempfd; 15655714Skris 15755714Skris jobcount = 0; 15855714Skris init(pp); /* set up capabilities */ 15955714Skris (void) write(1, "", 1); /* ack that daemon is started */ 16059191Skris (void) close(2); /* set up log file */ 16155714Skris if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 16255714Skris syslog(LOG_ERR, "%s: %m", pp->log_file); 16355714Skris (void) open(_PATH_DEVNULL, O_WRONLY); 16455714Skris } 16555714Skris setgid(getegid()); 16655714Skris pid = getpid(); /* for use with lprm */ 16755714Skris setpgrp(0, pid); 16859191Skris 16955714Skris /* 17055714Skris * At initial lpd startup, printjob may be called with various 17155714Skris * signal handlers in effect. After that initial startup, any 17255714Skris * calls to printjob will have a *different* set of signal-handlers 17355714Skris * in effect. Make sure all handlers are the ones we want. 17455714Skris */ 17555714Skris signal(SIGCHLD, SIG_DFL); 17655714Skris signal(SIGHUP, abortpr); 17755714Skris signal(SIGINT, abortpr); 17855714Skris signal(SIGQUIT, abortpr); 17955714Skris signal(SIGTERM, abortpr); 18055714Skris 18155714Skris /* 18255714Skris * uses short form file names 18355714Skris */ 18455714Skris if (chdir(pp->spool_dir) < 0) { 18559191Skris syslog(LOG_ERR, "%s: %m", pp->spool_dir); 18659191Skris exit(1); 18755714Skris } 18855714Skris if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 189100928Snectar exit(0); /* printing disabled */ 19055714Skris lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 19155714Skris LOCK_FILE_MODE); 192109998Smarkm if (lfd < 0) { 19355714Skris if (errno == EWOULDBLOCK) /* active daemon present */ 194109998Smarkm exit(0); 19555714Skris syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 19655714Skris exit(1); 19755714Skris } 19855714Skris /* turn off non-blocking mode (was turned on for lock effects only) */ 19955714Skris if (fcntl(lfd, F_SETFL, 0) < 0) { 20055714Skris syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 20155714Skris exit(1); 20255714Skris } 20355714Skris ftruncate(lfd, 0); 20455714Skris /* 20555714Skris * write process id for others to know 20655714Skris */ 20755714Skris sprintf(line, "%u\n", pid); 20855714Skris pidoff = i = strlen(line); 20955714Skris if (write(lfd, line, i) != i) { 21055714Skris syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 21155714Skris exit(1); 21255714Skris } 21355714Skris /* 21455714Skris * search the spool directory for work and sort by queue order. 21555714Skris */ 21655714Skris if ((nitems = getq(pp, &queue)) < 0) { 21755714Skris syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 21855714Skris pp->spool_dir); 21955714Skris exit(1); 22068651Skris } 22155714Skris if (nitems == 0) /* no work to do */ 222109998Smarkm exit(0); 22368651Skris if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 22468651Skris if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 22568651Skris syslog(LOG_ERR, "%s: %s: %m", pp->printer, 22668651Skris pp->lock_file); 22768651Skris } 22868651Skris 22955714Skris /* create a file which will be used to hold stderr from filters */ 23055714Skris if ((tempfd = mkstemp(tempstderr)) == -1) { 23155714Skris syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 23255714Skris tempstderr); 23355714Skris exit(1); 23455714Skris } 23555714Skris if ((i = fchmod(tempfd, 0664)) == -1) { 23655714Skris syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 23755714Skris tempstderr); 238109998Smarkm exit(1); 239109998Smarkm } 24059191Skris /* lpd doesn't need it to be open, it just needs it to exist */ 24159191Skris close(tempfd); 24259191Skris 24359191Skris openpr(pp); /* open printer or remote */ 24459191Skrisagain: 24559191Skris /* 24659191Skris * we found something to do now do it -- 24759191Skris * write the name of the current control file into the lock file 24855714Skris * so the spool queue program can tell what we're working on 24955714Skris */ 25059191Skris for (qp = queue; nitems--; free((char *) q)) { 25155714Skris q = *qp++; 25255714Skris if (stat(q->job_cfname, &stb) < 0) 25359191Skris continue; 25455714Skris errcnt = 0; 25555714Skris restart: 25655714Skris (void) lseek(lfd, pidoff, 0); 25755714Skris (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 25855714Skris i = strlen(line); 25955714Skris if (write(lfd, line, i) != i) 26055714Skris syslog(LOG_ERR, "%s: %s: %m", pp->printer, 26155714Skris pp->lock_file); 26255714Skris if (!pp->remote) 26355714Skris i = printit(pp, q->job_cfname); 26455714Skris else 26555714Skris i = sendit(pp, q->job_cfname); 26655714Skris /* 26755714Skris * Check to see if we are supposed to stop printing or 26855714Skris * if we are to rebuild the queue. 26955714Skris */ 27055714Skris if (fstat(lfd, &stb) == 0) { 27155714Skris /* stop printing before starting next job? */ 27255714Skris if (stb.st_mode & LFM_PRINT_DIS) 27355714Skris goto done; 27455714Skris /* rebuild queue (after lpc topq) */ 27555714Skris if (stb.st_mode & LFM_RESET_QUE) { 27655714Skris for (free(q); nitems--; free(q)) 27755714Skris q = *qp++; 27855714Skris if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 27955714Skris < 0) 28055714Skris syslog(LOG_WARNING, "%s: %s: %m", 28155714Skris pp->printer, pp->lock_file); 28255714Skris break; 28355714Skris } 28455714Skris } 28568651Skris if (i == OK) /* all files of this job printed */ 28655714Skris jobcount++; 28755714Skris else if (i == REPRINT && ++errcnt < 5) { 28868651Skris /* try reprinting the job */ 28955714Skris syslog(LOG_INFO, "restarting %s", pp->printer); 29055714Skris if (ofilter > 0) { 29155714Skris kill(ofilter, SIGCONT); /* to be sure */ 29255714Skris (void) close(ofd); 29355714Skris while ((i = wait(NULL)) > 0 && i != ofilter) 29455714Skris ; 29555714Skris if (i < 0) 29655714Skris syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m", 29755714Skris pp->printer, ofilter); 29855714Skris ofilter = 0; 29955714Skris } 30055714Skris (void) close(pfd); /* close printer */ 30155714Skris if (ftruncate(lfd, pidoff) < 0) 30255714Skris syslog(LOG_WARNING, "%s: %s: %m", 30355714Skris pp->printer, pp->lock_file); 30455714Skris openpr(pp); /* try to reopen printer */ 30555714Skris goto restart; 30655714Skris } else { 30755714Skris syslog(LOG_WARNING, "%s: job could not be %s (%s)", 30855714Skris pp->printer, 30955714Skris pp->remote ? "sent to remote host" : "printed", 31055714Skris q->job_cfname); 31155714Skris if (i == REPRINT) { 31255714Skris /* ensure we don't attempt this job again */ 31355714Skris (void) unlink(q->job_cfname); 31455714Skris q->job_cfname[0] = 'd'; 31555714Skris (void) unlink(q->job_cfname); 31655714Skris if (logname[0]) 31755714Skris sendmail(pp, logname, FATALERR); 31855714Skris } 31955714Skris } 32055714Skris } 32155714Skris free(queue); 32255714Skris /* 32355714Skris * search the spool directory for more work. 32455714Skris */ 32555714Skris if ((nitems = getq(pp, &queue)) < 0) { 32655714Skris syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 32755714Skris pp->spool_dir); 32872613Skris exit(1); 32955714Skris } 33055714Skris if (nitems == 0) { /* no more work to do */ 33155714Skris done: 33255714Skris if (jobcount > 0) { /* jobs actually printed */ 33355714Skris if (!pp->no_formfeed && !pp->tof) 33455714Skris (void) write(ofd, pp->form_feed, 33555714Skris strlen(pp->form_feed)); 33655714Skris if (pp->trailer != NULL) /* output trailer */ 33755714Skris (void) write(ofd, pp->trailer, 33855714Skris strlen(pp->trailer)); 33955714Skris } 34055714Skris (void) close(ofd); 34155714Skris (void) wait(NULL); 34255714Skris (void) unlink(tempstderr); 34355714Skris exit(0); 34455714Skris } 34559191Skris goto again; 34655714Skris} 34755714Skris 34855714Skrischar fonts[4][50]; /* fonts for troff */ 34955714Skris 35055714Skrischar ifonts[4][40] = { 35155714Skris _PATH_VFONTR, 35255714Skris _PATH_VFONTI, 35355714Skris _PATH_VFONTB, 35459191Skris _PATH_VFONTS, 35555714Skris}; 35655714Skris 35755714Skris/* 35855714Skris * The remaining part is the reading of the control file (cf) 35955714Skris * and performing the various actions. 36055714Skris */ 36155714Skrisstatic int 36255714Skrisprintit(struct printer *pp, char *file) 36355714Skris{ 36455714Skris register int i; 36555714Skris char *cp; 36655714Skris int bombed, didignorehdr; 36759191Skris 36859191Skris bombed = OK; 36955714Skris didignorehdr = 0; 37055714Skris /* 37155714Skris * open control file; ignore if no longer there. 37268651Skris */ 37355714Skris if ((cfp = fopen(file, "r")) == NULL) { 374109998Smarkm syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 375109998Smarkm return(OK); 37655714Skris } 37755714Skris /* 37859191Skris * Reset troff fonts. 37955714Skris */ 38055714Skris for (i = 0; i < 4; i++) 38155714Skris strcpy(fonts[i], ifonts[i]); 38255714Skris sprintf(&width[2], "%ld", pp->page_width); 38355714Skris strcpy(indent+2, "0"); 38455714Skris 38555714Skris /* initialize job-specific count of datafiles processed */ 38659191Skris job_dfcnt = 0; 38759191Skris 38855714Skris /* 38955714Skris * read the control file for work to do 39055714Skris * 39155714Skris * file format -- first character in the line is a command 39255714Skris * rest of the line is the argument. 393 * valid commands are: 394 * 395 * S -- "stat info" for symbolic link protection 396 * J -- "job name" on banner page 397 * C -- "class name" on banner page 398 * L -- "literal" user's name to print on banner 399 * T -- "title" for pr 400 * H -- "host name" of machine where lpr was done 401 * P -- "person" user's login name 402 * I -- "indent" amount to indent output 403 * R -- laser dpi "resolution" 404 * f -- "file name" name of text file to print 405 * l -- "file name" text file with control chars 406 * p -- "file name" text file to print with pr(1) 407 * t -- "file name" troff(1) file to print 408 * n -- "file name" ditroff(1) file to print 409 * d -- "file name" dvi file to print 410 * g -- "file name" plot(1G) file to print 411 * v -- "file name" plain raster file to print 412 * c -- "file name" cifplot file to print 413 * 1 -- "R font file" for troff 414 * 2 -- "I font file" for troff 415 * 3 -- "B font file" for troff 416 * 4 -- "S font file" for troff 417 * N -- "name" of file (used by lpq) 418 * U -- "unlink" name of file to remove 419 * (after we print it. (Pass 2 only)). 420 * M -- "mail" to user when done printing 421 * Z -- "locale" for pr 422 * 423 * getline reads a line and expands tabs to blanks 424 */ 425 426 /* pass 1 */ 427 428 while (getline(cfp)) 429 switch (line[0]) { 430 case 'H': 431 strlcpy(origin_host, line + 1, sizeof(origin_host)); 432 if (class[0] == '\0') { 433 strncpy(class, line+1, sizeof(class) - 1); 434 class[sizeof(class) - 1] = '\0'; 435 } 436 continue; 437 438 case 'P': 439 strncpy(logname, line+1, sizeof(logname) - 1); 440 logname[sizeof(logname) - 1] = '\0'; 441 if (pp->restricted) { /* restricted */ 442 if (getpwnam(logname) == NULL) { 443 bombed = NOACCT; 444 sendmail(pp, line+1, bombed); 445 goto pass2; 446 } 447 } 448 continue; 449 450 case 'S': 451 cp = line+1; 452 i = 0; 453 while (*cp >= '0' && *cp <= '9') 454 i = i * 10 + (*cp++ - '0'); 455 fdev = i; 456 cp++; 457 i = 0; 458 while (*cp >= '0' && *cp <= '9') 459 i = i * 10 + (*cp++ - '0'); 460 fino = i; 461 continue; 462 463 case 'J': 464 if (line[1] != '\0') { 465 strncpy(jobname, line+1, sizeof(jobname) - 1); 466 jobname[sizeof(jobname) - 1] = '\0'; 467 } else 468 strcpy(jobname, " "); 469 continue; 470 471 case 'C': 472 if (line[1] != '\0') 473 strncpy(class, line+1, sizeof(class) - 1); 474 else if (class[0] == '\0') 475 gethostname(class, sizeof(class)); 476 class[sizeof(class) - 1] = '\0'; 477 continue; 478 479 case 'T': /* header title for pr */ 480 strncpy(title, line+1, sizeof(title) - 1); 481 title[sizeof(title) - 1] = '\0'; 482 continue; 483 484 case 'L': /* identification line */ 485 if (!pp->no_header && !pp->header_last) 486 banner(pp, line+1, jobname); 487 continue; 488 489 case '1': /* troff fonts */ 490 case '2': 491 case '3': 492 case '4': 493 if (line[1] != '\0') { 494 strncpy(fonts[line[0]-'1'], line+1, 495 50-1); 496 fonts[line[0]-'1'][50-1] = '\0'; 497 } 498 continue; 499 500 case 'W': /* page width */ 501 strncpy(width+2, line+1, sizeof(width) - 3); 502 width[2+sizeof(width) - 3] = '\0'; 503 continue; 504 505 case 'I': /* indent amount */ 506 strncpy(indent+2, line+1, sizeof(indent) - 3); 507 indent[2+sizeof(indent) - 3] = '\0'; 508 continue; 509 510 case 'Z': /* locale for pr */ 511 strncpy(locale, line+1, sizeof(locale) - 1); 512 locale[sizeof(locale) - 1] = '\0'; 513 continue; 514 515 default: /* some file to print */ 516 /* only lowercase cmd-codes include a file-to-print */ 517 if ((line[0] < 'a') || (line[0] > 'z')) { 518 /* ignore any other lines */ 519 if (lflag <= 1) 520 continue; 521 if (!didignorehdr) { 522 syslog(LOG_INFO, "%s: in %s :", 523 pp->printer, file); 524 didignorehdr = 1; 525 } 526 syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 527 pp->printer, line[0], &line[1]); 528 continue; 529 } 530 i = print(pp, line[0], line+1); 531 switch (i) { 532 case ERROR: 533 if (bombed == OK) 534 bombed = FATALERR; 535 break; 536 case REPRINT: 537 (void) fclose(cfp); 538 return(REPRINT); 539 case FILTERERR: 540 case ACCESS: 541 bombed = i; 542 sendmail(pp, logname, bombed); 543 } 544 title[0] = '\0'; 545 continue; 546 547 case 'N': 548 case 'U': 549 case 'M': 550 case 'R': 551 continue; 552 } 553 554 /* pass 2 */ 555 556pass2: 557 fseek(cfp, 0L, 0); 558 while (getline(cfp)) 559 switch (line[0]) { 560 case 'L': /* identification line */ 561 if (!pp->no_header && pp->header_last) 562 banner(pp, line+1, jobname); 563 continue; 564 565 case 'M': 566 if (bombed < NOACCT) /* already sent if >= NOACCT */ 567 sendmail(pp, line+1, bombed); 568 continue; 569 570 case 'U': 571 if (strchr(line+1, '/')) 572 continue; 573 (void) unlink(line+1); 574 } 575 /* 576 * clean-up in case another control file exists 577 */ 578 (void) fclose(cfp); 579 (void) unlink(file); 580 return(bombed == OK ? OK : ERROR); 581} 582 583/* 584 * Print a file. 585 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 586 * Return -1 if a non-recoverable error occured, 587 * 2 if the filter detected some errors (but printed the job anyway), 588 * 1 if we should try to reprint this job and 589 * 0 if all is well. 590 * Note: all filters take stdin as the file, stdout as the printer, 591 * stderr as the log file, and must not ignore SIGINT. 592 */ 593static int 594print(struct printer *pp, int format, char *file) 595{ 596 register int n, i; 597 register char *prog; 598 int fi, fo; 599 FILE *fp; 600 char *av[15], buf[BUFSIZ]; 601 int pid, p[2], stopped; 602 union wait status; 603 struct stat stb; 604 605 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 606 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 607 pp->printer, file, format); 608 return(ERROR); 609 } 610 /* 611 * Check to see if data file is a symbolic link. If so, it should 612 * still point to the same file or someone is trying to print 613 * something he shouldn't. 614 */ 615 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 616 (stb.st_dev != fdev || stb.st_ino != fino)) 617 return(ACCESS); 618 619 job_dfcnt++; /* increment datafile counter for this job */ 620 stopped = 0; /* output filter is not stopped */ 621 622 /* everything seems OK, start it up */ 623 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 624 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 625 pp->tof = 1; 626 } 627 if (pp->filters[LPF_INPUT] == NULL 628 && (format == 'f' || format == 'l')) { 629 pp->tof = 0; 630 while ((n = read(fi, buf, BUFSIZ)) > 0) 631 if (write(ofd, buf, n) != n) { 632 (void) close(fi); 633 return(REPRINT); 634 } 635 (void) close(fi); 636 return(OK); 637 } 638 switch (format) { 639 case 'p': /* print file using 'pr' */ 640 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 641 prog = _PATH_PR; 642 i = 0; 643 av[i++] = "pr"; 644 av[i++] = width; 645 av[i++] = length; 646 av[i++] = "-h"; 647 av[i++] = *title ? title : " "; 648 av[i++] = "-L"; 649 av[i++] = *locale ? locale : "C"; 650 av[i++] = "-F"; 651 av[i] = 0; 652 fo = ofd; 653 goto start; 654 } 655 pipe(p); 656 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 657 dup2(fi, 0); /* file is stdin */ 658 dup2(p[1], 1); /* pipe is stdout */ 659 closelog(); 660 closeallfds(3); 661 execl(_PATH_PR, "pr", width, length, 662 "-h", *title ? title : " ", 663 "-L", *locale ? locale : "C", 664 "-F", (char *)0); 665 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 666 exit(2); 667 } 668 (void) close(p[1]); /* close output side */ 669 (void) close(fi); 670 if (prchild < 0) { 671 prchild = 0; 672 (void) close(p[0]); 673 return(ERROR); 674 } 675 fi = p[0]; /* use pipe for input */ 676 case 'f': /* print plain text file */ 677 prog = pp->filters[LPF_INPUT]; 678 av[1] = width; 679 av[2] = length; 680 av[3] = indent; 681 n = 4; 682 break; 683 case 'l': /* like 'f' but pass control characters */ 684 prog = pp->filters[LPF_INPUT]; 685 av[1] = "-c"; 686 av[2] = width; 687 av[3] = length; 688 av[4] = indent; 689 n = 5; 690 break; 691 case 'r': /* print a fortran text file */ 692 prog = pp->filters[LPF_FORTRAN]; 693 av[1] = width; 694 av[2] = length; 695 n = 3; 696 break; 697 case 't': /* print troff output */ 698 case 'n': /* print ditroff output */ 699 case 'd': /* print tex output */ 700 (void) unlink(".railmag"); 701 if ((fo = creat(".railmag", FILMOD)) < 0) { 702 syslog(LOG_ERR, "%s: cannot create .railmag", 703 pp->printer); 704 (void) unlink(".railmag"); 705 } else { 706 for (n = 0; n < 4; n++) { 707 if (fonts[n][0] != '/') 708 (void) write(fo, _PATH_VFONT, 709 sizeof(_PATH_VFONT) - 1); 710 (void) write(fo, fonts[n], strlen(fonts[n])); 711 (void) write(fo, "\n", 1); 712 } 713 (void) close(fo); 714 } 715 prog = (format == 't') ? pp->filters[LPF_TROFF] 716 : ((format == 'n') ? pp->filters[LPF_DITROFF] 717 : pp->filters[LPF_DVI]); 718 av[1] = pxwidth; 719 av[2] = pxlength; 720 n = 3; 721 break; 722 case 'c': /* print cifplot output */ 723 prog = pp->filters[LPF_CIFPLOT]; 724 av[1] = pxwidth; 725 av[2] = pxlength; 726 n = 3; 727 break; 728 case 'g': /* print plot(1G) output */ 729 prog = pp->filters[LPF_GRAPH]; 730 av[1] = pxwidth; 731 av[2] = pxlength; 732 n = 3; 733 break; 734 case 'v': /* print raster output */ 735 prog = pp->filters[LPF_RASTER]; 736 av[1] = pxwidth; 737 av[2] = pxlength; 738 n = 3; 739 break; 740 default: 741 (void) close(fi); 742 syslog(LOG_ERR, "%s: illegal format character '%c'", 743 pp->printer, format); 744 return(ERROR); 745 } 746 if (prog == NULL) { 747 (void) close(fi); 748 syslog(LOG_ERR, 749 "%s: no filter found in printcap for format character '%c'", 750 pp->printer, format); 751 return(ERROR); 752 } 753 if ((av[0] = strrchr(prog, '/')) != NULL) 754 av[0]++; 755 else 756 av[0] = prog; 757 av[n++] = "-n"; 758 av[n++] = logname; 759 av[n++] = "-h"; 760 av[n++] = origin_host; 761 av[n++] = pp->acct_file; 762 av[n] = 0; 763 fo = pfd; 764 if (ofilter > 0) { /* stop output filter */ 765 write(ofd, "\031\1", 2); 766 while ((pid = 767 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 768 ; 769 if (pid < 0) 770 syslog(LOG_WARNING, "%s: after stopping 'of', wait3() returned: %m", 771 pp->printer); 772 else if (status.w_stopval != WSTOPPED) { 773 (void) close(fi); 774 syslog(LOG_WARNING, 775 "%s: output filter died " 776 "(pid=%d retcode=%d termsig=%d)", 777 pp->printer, ofilter, status.w_retcode, 778 status.w_termsig); 779 return(REPRINT); 780 } 781 stopped++; 782 } 783start: 784 if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 785 dup2(fi, 0); 786 dup2(fo, 1); 787 /* setup stderr for the filter (child process) 788 * so it goes to our temporary errors file */ 789 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 790 if (n >= 0) 791 dup2(n, 2); 792 closelog(); 793 closeallfds(3); 794 execv(prog, av); 795 syslog(LOG_ERR, "cannot execv %s", prog); 796 exit(2); 797 } 798 (void) close(fi); 799 if (child < 0) 800 status.w_retcode = 100; 801 else { 802 while ((pid = wait((int *)&status)) > 0 && pid != child) 803 ; 804 if (pid < 0) { 805 status.w_retcode = 100; 806 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 807 pp->printer, prog); 808 } 809 } 810 child = 0; 811 prchild = 0; 812 if (stopped) { /* restart output filter */ 813 if (kill(ofilter, SIGCONT) < 0) { 814 syslog(LOG_ERR, "cannot restart output filter"); 815 exit(1); 816 } 817 } 818 pp->tof = 0; 819 820 /* Copy the filter's output to "lf" logfile */ 821 if ((fp = fopen(tempstderr, "r"))) { 822 while (fgets(buf, sizeof(buf), fp)) 823 fputs(buf, stderr); 824 fclose(fp); 825 } 826 827 if (!WIFEXITED(status)) { 828 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 829 pp->printer, format, status.w_termsig); 830 return(ERROR); 831 } 832 switch (status.w_retcode) { 833 case 0: 834 pp->tof = 1; 835 return(OK); 836 case 1: 837 return(REPRINT); 838 case 2: 839 return(ERROR); 840 default: 841 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 842 pp->printer, format, status.w_retcode); 843 return(FILTERERR); 844 } 845} 846 847/* 848 * Send the daemon control file (cf) and any data files. 849 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 850 * 0 if all is well. 851 */ 852static int 853sendit(struct printer *pp, char *file) 854{ 855 register int i, err = OK; 856 char *cp, last[BUFSIZ]; 857 858 /* 859 * open control file 860 */ 861 if ((cfp = fopen(file, "r")) == NULL) 862 return(OK); 863 864 /* initialize job-specific count of datafiles processed */ 865 job_dfcnt = 0; 866 867 /* 868 * read the control file for work to do 869 * 870 * file format -- first character in the line is a command 871 * rest of the line is the argument. 872 * commands of interest are: 873 * 874 * a-z -- "file name" name of file to print 875 * U -- "unlink" name of file to remove 876 * (after we print it. (Pass 2 only)). 877 */ 878 879 /* 880 * pass 1 881 */ 882 while (getline(cfp)) { 883 again: 884 if (line[0] == 'S') { 885 cp = line+1; 886 i = 0; 887 while (*cp >= '0' && *cp <= '9') 888 i = i * 10 + (*cp++ - '0'); 889 fdev = i; 890 cp++; 891 i = 0; 892 while (*cp >= '0' && *cp <= '9') 893 i = i * 10 + (*cp++ - '0'); 894 fino = i; 895 } else if (line[0] == 'H') { 896 strlcpy(origin_host, line + 1, sizeof(origin_host)); 897 if (class[0] == '\0') { 898 strncpy(class, line+1, sizeof(class) - 1); 899 class[sizeof(class) - 1] = '\0'; 900 } 901 } else if (line[0] == 'P') { 902 strncpy(logname, line+1, sizeof(logname) - 1); 903 logname[sizeof(logname) - 1] = '\0'; 904 if (pp->restricted) { /* restricted */ 905 if (getpwnam(logname) == NULL) { 906 sendmail(pp, line+1, NOACCT); 907 err = ERROR; 908 break; 909 } 910 } 911 } else if (line[0] == 'I') { 912 strncpy(indent+2, line+1, sizeof(indent) - 3); 913 indent[2 + sizeof(indent) - 3] = '\0'; 914 } else if (line[0] >= 'a' && line[0] <= 'z') { 915 strcpy(last, line); 916 while ((i = getline(cfp)) != 0) 917 if (strcmp(last, line)) 918 break; 919 switch (sendfile(pp, '\3', last+1, *last)) { 920 case OK: 921 if (i) 922 goto again; 923 break; 924 case REPRINT: 925 (void) fclose(cfp); 926 return(REPRINT); 927 case ACCESS: 928 sendmail(pp, logname, ACCESS); 929 case ERROR: 930 err = ERROR; 931 } 932 break; 933 } 934 } 935 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 936 (void) fclose(cfp); 937 return(REPRINT); 938 } 939 /* 940 * pass 2 941 */ 942 fseek(cfp, 0L, 0); 943 while (getline(cfp)) 944 if (line[0] == 'U' && !strchr(line+1, '/')) 945 (void) unlink(line+1); 946 /* 947 * clean-up in case another control file exists 948 */ 949 (void) fclose(cfp); 950 (void) unlink(file); 951 return(err); 952} 953 954/* 955 * Send a data file to the remote machine and spool it. 956 * Return positive if we should try resending. 957 */ 958static int 959sendfile(struct printer *pp, int type, char *file, char format) 960{ 961 register int f, i, amt; 962 struct stat stb; 963 FILE *fp; 964 char buf[BUFSIZ]; 965 int closedpr, resp, sizerr, statrc; 966 967 statrc = lstat(file, &stb); 968 if (statrc < 0) { 969 syslog(LOG_ERR, "%s: error from lstat(%s): %m", 970 pp->printer, file); 971 return(ERROR); 972 } 973 f = open(file, O_RDONLY); 974 if (f < 0) { 975 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 976 pp->printer, file); 977 return(ERROR); 978 } 979 /* 980 * Check to see if data file is a symbolic link. If so, it should 981 * still point to the same file or someone is trying to print something 982 * he shouldn't. 983 */ 984 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 985 (stb.st_dev != fdev || stb.st_ino != fino)) 986 return(ACCESS); 987 988 job_dfcnt++; /* increment datafile counter for this job */ 989 990 /* everything seems OK, start it up */ 991 sizerr = 0; 992 closedpr = 0; 993 if (type == '\3') { 994 if (pp->filters[LPF_INPUT]) { 995 /* 996 * We're sending something with an ifilter. We have to 997 * run the ifilter and store the output as a temporary 998 * spool file (tfile...), because the protocol requires 999 * us to send the file size before we start sending any 1000 * of the data. 1001 */ 1002 char *av[15]; 1003 int n; 1004 int ifilter; 1005 union wait status; /* XXX */ 1006 1007 strcpy(tfile,TFILENAME); 1008 if ((tfd = mkstemp(tfile)) == -1) { 1009 syslog(LOG_ERR, "mkstemp: %m"); 1010 return(ERROR); 1011 } 1012 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 1013 av[0] = pp->filters[LPF_INPUT]; 1014 else 1015 av[0]++; 1016 if (format == 'l') 1017 av[n=1] = "-c"; 1018 else 1019 n = 0; 1020 av[++n] = width; 1021 av[++n] = length; 1022 av[++n] = indent; 1023 av[++n] = "-n"; 1024 av[++n] = logname; 1025 av[++n] = "-h"; 1026 av[++n] = origin_host; 1027 av[++n] = pp->acct_file; 1028 av[++n] = 0; 1029 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 1030 dup2(f, 0); 1031 dup2(tfd, 1); 1032 /* setup stderr for the filter (child process) 1033 * so it goes to our temporary errors file */ 1034 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1035 if (n >= 0) 1036 dup2(n, 2); 1037 closelog(); 1038 closeallfds(3); 1039 execv(pp->filters[LPF_INPUT], av); 1040 syslog(LOG_ERR, "cannot execv %s", 1041 pp->filters[LPF_INPUT]); 1042 exit(2); 1043 } 1044 (void) close(f); 1045 if (ifilter < 0) 1046 status.w_retcode = 100; 1047 else { 1048 while ((pid = wait((int *)&status)) > 0 && 1049 pid != ifilter) 1050 ; 1051 if (pid < 0) { 1052 status.w_retcode = 100; 1053 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 1054 pp->printer, pp->filters[LPF_INPUT]); 1055 } 1056 } 1057 /* Copy the filter's output to "lf" logfile */ 1058 if ((fp = fopen(tempstderr, "r"))) { 1059 while (fgets(buf, sizeof(buf), fp)) 1060 fputs(buf, stderr); 1061 fclose(fp); 1062 } 1063 /* process the return-code from the filter */ 1064 switch (status.w_retcode) { 1065 case 0: 1066 break; 1067 case 1: 1068 unlink(tfile); 1069 return(REPRINT); 1070 case 2: 1071 unlink(tfile); 1072 return(ERROR); 1073 default: 1074 syslog(LOG_WARNING, "%s: filter '%c' exited" 1075 " (retcode=%d)", 1076 pp->printer, format, status.w_retcode); 1077 unlink(tfile); 1078 return(FILTERERR); 1079 } 1080 statrc = fstat(tfd, &stb); /* to find size of tfile */ 1081 if (statrc < 0) { 1082 syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m", 1083 pp->printer, tfile); 1084 return(ERROR); 1085 } 1086 f = tfd; 1087 lseek(f,0,SEEK_SET); 1088 } else if (ofilter) { 1089 /* 1090 * We're sending something with an ofilter, we have to 1091 * store the output as a temporary file (tfile)... the 1092 * protocol requires us to send the file size 1093 */ 1094 int i; 1095 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1096 amt = BUFSIZ; 1097 if (i + amt > stb.st_size) 1098 amt = stb.st_size - i; 1099 if (sizerr == 0 && read(f, buf, amt) != amt) { 1100 sizerr = 1; 1101 break; 1102 } 1103 if (write(ofd, buf, amt) != amt) { 1104 (void) close(f); 1105 return(REPRINT); 1106 } 1107 } 1108 close(ofd); 1109 close(f); 1110 while ((i = wait(NULL)) > 0 && i != ofilter) 1111 ; 1112 if (i < 0) 1113 syslog(LOG_WARNING, "%s: after closing 'of', wait() returned: %m", 1114 pp->printer); 1115 ofilter = 0; 1116 statrc = fstat(tfd, &stb); /* to find size of tfile */ 1117 if (statrc < 0) { 1118 syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m", 1119 pp->printer, tfile); 1120 openpr(pp); 1121 return(ERROR); 1122 } 1123 f = tfd; 1124 lseek(f,0,SEEK_SET); 1125 closedpr = 1; 1126 } 1127 } 1128 1129 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1130 amt = strlen(buf); 1131 for (i = 0; ; i++) { 1132 if (write(pfd, buf, amt) != amt || 1133 (resp = response(pp)) < 0 || resp == '\1') { 1134 (void) close(f); 1135 if (tfd != -1 && type == '\3') { 1136 tfd = -1; 1137 unlink(tfile); 1138 if (closedpr) 1139 openpr(pp); 1140 } 1141 return(REPRINT); 1142 } else if (resp == '\0') 1143 break; 1144 if (i == 0) 1145 pstatus(pp, 1146 "no space on remote; waiting for queue to drain"); 1147 if (i == 10) 1148 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1149 pp->printer, pp->remote_host); 1150 sleep(5 * 60); 1151 } 1152 if (i) 1153 pstatus(pp, "sending to %s", pp->remote_host); 1154 if (type == '\3') 1155 trstat_init(pp, file, job_dfcnt); 1156 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1157 amt = BUFSIZ; 1158 if (i + amt > stb.st_size) 1159 amt = stb.st_size - i; 1160 if (sizerr == 0 && read(f, buf, amt) != amt) 1161 sizerr = 1; 1162 if (write(pfd, buf, amt) != amt) { 1163 (void) close(f); 1164 if (tfd != -1 && type == '\3') { 1165 tfd = -1; 1166 unlink(tfile); 1167 if (closedpr) 1168 openpr(pp); 1169 } 1170 return(REPRINT); 1171 } 1172 } 1173 1174 (void) close(f); 1175 if (tfd != -1 && type == '\3') { 1176 tfd = -1; 1177 unlink(tfile); 1178 } 1179 if (sizerr) { 1180 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1181 /* tell recvjob to ignore this file */ 1182 (void) write(pfd, "\1", 1); 1183 if (closedpr) 1184 openpr(pp); 1185 return(ERROR); 1186 } 1187 if (write(pfd, "", 1) != 1 || response(pp)) { 1188 if (closedpr) 1189 openpr(pp); 1190 return(REPRINT); 1191 } 1192 if (closedpr) 1193 openpr(pp); 1194 if (type == '\3') 1195 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1196 pp->remote_host, origin_host); 1197 return(OK); 1198} 1199 1200/* 1201 * Check to make sure there have been no errors and that both programs 1202 * are in sync with eachother. 1203 * Return non-zero if the connection was lost. 1204 */ 1205static char 1206response(const struct printer *pp) 1207{ 1208 char resp; 1209 1210 if (read(pfd, &resp, 1) != 1) { 1211 syslog(LOG_INFO, "%s: lost connection", pp->printer); 1212 return(-1); 1213 } 1214 return(resp); 1215} 1216 1217/* 1218 * Banner printing stuff 1219 */ 1220static void 1221banner(struct printer *pp, char *name1, char *name2) 1222{ 1223 time_t tvec; 1224 1225 time(&tvec); 1226 if (!pp->no_formfeed && !pp->tof) 1227 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1228 if (pp->short_banner) { /* short banner only */ 1229 if (class[0]) { 1230 (void) write(ofd, class, strlen(class)); 1231 (void) write(ofd, ":", 1); 1232 } 1233 (void) write(ofd, name1, strlen(name1)); 1234 (void) write(ofd, " Job: ", 7); 1235 (void) write(ofd, name2, strlen(name2)); 1236 (void) write(ofd, " Date: ", 8); 1237 (void) write(ofd, ctime(&tvec), 24); 1238 (void) write(ofd, "\n", 1); 1239 } else { /* normal banner */ 1240 (void) write(ofd, "\n\n\n", 3); 1241 scan_out(pp, ofd, name1, '\0'); 1242 (void) write(ofd, "\n\n", 2); 1243 scan_out(pp, ofd, name2, '\0'); 1244 if (class[0]) { 1245 (void) write(ofd,"\n\n\n",3); 1246 scan_out(pp, ofd, class, '\0'); 1247 } 1248 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1249 (void) write(ofd, name2, strlen(name2)); 1250 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1251 (void) write(ofd, ctime(&tvec), 24); 1252 (void) write(ofd, "\n", 1); 1253 } 1254 if (!pp->no_formfeed) 1255 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1256 pp->tof = 1; 1257} 1258 1259static char * 1260scnline(int key, char *p, int c) 1261{ 1262 register int scnwidth; 1263 1264 for (scnwidth = WIDTH; --scnwidth;) { 1265 key <<= 1; 1266 *p++ = key & 0200 ? c : BACKGND; 1267 } 1268 return (p); 1269} 1270 1271#define TRC(q) (((q)-' ')&0177) 1272 1273static void 1274scan_out(struct printer *pp, int scfd, char *scsp, int dlm) 1275{ 1276 register char *strp; 1277 register int nchrs, j; 1278 char outbuf[LINELEN+1], *sp, c, cc; 1279 int d, scnhgt; 1280 1281 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1282 strp = &outbuf[0]; 1283 sp = scsp; 1284 for (nchrs = 0; ; ) { 1285 d = dropit(c = TRC(cc = *sp++)); 1286 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1287 for (j = WIDTH; --j;) 1288 *strp++ = BACKGND; 1289 else 1290 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1291 if (*sp == dlm || *sp == '\0' || 1292 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1293 break; 1294 *strp++ = BACKGND; 1295 *strp++ = BACKGND; 1296 } 1297 while (*--strp == BACKGND && strp >= outbuf) 1298 ; 1299 strp++; 1300 *strp++ = '\n'; 1301 (void) write(scfd, outbuf, strp-outbuf); 1302 } 1303} 1304 1305static int 1306dropit(int c) 1307{ 1308 switch(c) { 1309 1310 case TRC('_'): 1311 case TRC(';'): 1312 case TRC(','): 1313 case TRC('g'): 1314 case TRC('j'): 1315 case TRC('p'): 1316 case TRC('q'): 1317 case TRC('y'): 1318 return (DROP); 1319 1320 default: 1321 return (0); 1322 } 1323} 1324 1325/* 1326 * sendmail --- 1327 * tell people about job completion 1328 */ 1329static void 1330sendmail(struct printer *pp, char *user, int bombed) 1331{ 1332 register int i; 1333 int p[2], s; 1334 register const char *cp; 1335 struct stat stb; 1336 FILE *fp; 1337 1338 pipe(p); 1339 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1340 dup2(p[0], 0); 1341 closelog(); 1342 closeallfds(3); 1343 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1344 cp++; 1345 else 1346 cp = _PATH_SENDMAIL; 1347 execl(_PATH_SENDMAIL, cp, "-t", (char *)0); 1348 _exit(0); 1349 } else if (s > 0) { /* parent */ 1350 dup2(p[1], 1); 1351 printf("To: %s@%s\n", user, origin_host); 1352 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1353 *jobname ? jobname : "<unknown>"); 1354 printf("Reply-To: root@%s\n\n", local_host); 1355 printf("Your printer job "); 1356 if (*jobname) 1357 printf("(%s) ", jobname); 1358 1359 cp = "XXX compiler confusion"; /* XXX shut GCC up */ 1360 switch (bombed) { 1361 case OK: 1362 printf("\ncompleted successfully\n"); 1363 cp = "OK"; 1364 break; 1365 default: 1366 case FATALERR: 1367 printf("\ncould not be printed\n"); 1368 cp = "FATALERR"; 1369 break; 1370 case NOACCT: 1371 printf("\ncould not be printed without an account on %s\n", 1372 local_host); 1373 cp = "NOACCT"; 1374 break; 1375 case FILTERERR: 1376 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1377 || (fp = fopen(tempstderr, "r")) == NULL) { 1378 printf("\nhad some errors and may not have printed\n"); 1379 break; 1380 } 1381 printf("\nhad the following errors and may not have printed:\n"); 1382 while ((i = getc(fp)) != EOF) 1383 putchar(i); 1384 (void) fclose(fp); 1385 cp = "FILTERERR"; 1386 break; 1387 case ACCESS: 1388 printf("\nwas not printed because it was not linked to the original file\n"); 1389 cp = "ACCESS"; 1390 } 1391 fflush(stdout); 1392 (void) close(1); 1393 } else { 1394 syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 1395 return; 1396 } 1397 (void) close(p[0]); 1398 (void) close(p[1]); 1399 wait(NULL); 1400 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1401 user, *jobname ? jobname : "<unknown>", pp->printer, cp); 1402} 1403 1404/* 1405 * dofork - fork with retries on failure 1406 */ 1407static int 1408dofork(const struct printer *pp, int action) 1409{ 1410 register int i, forkpid; 1411 struct passwd *pwd; 1412 1413 for (i = 0; i < 20; i++) { 1414 if ((forkpid = fork()) < 0) { 1415 sleep((unsigned)(i*i)); 1416 continue; 1417 } 1418 /* 1419 * Child should run as daemon instead of root 1420 */ 1421 if (forkpid == 0) { 1422 if ((pwd = getpwuid(pp->daemon_user)) == NULL) { 1423 syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", 1424 pp->daemon_user); 1425 break; 1426 } 1427 initgroups(pwd->pw_name, pwd->pw_gid); 1428 setgid(pwd->pw_gid); 1429 setuid(pp->daemon_user); 1430 } 1431 return(forkpid); 1432 } 1433 syslog(LOG_ERR, "can't fork"); 1434 1435 switch (action) { 1436 case DORETURN: 1437 return (-1); 1438 default: 1439 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1440 /*FALL THRU*/ 1441 case DOABORT: 1442 exit(1); 1443 } 1444 /*NOTREACHED*/ 1445} 1446 1447/* 1448 * Kill child processes to abort current job. 1449 */ 1450static void 1451abortpr(int signo __unused) 1452{ 1453 1454 (void) unlink(tempstderr); 1455 kill(0, SIGINT); 1456 if (ofilter > 0) 1457 kill(ofilter, SIGCONT); 1458 while (wait(NULL) > 0) 1459 ; 1460 if (ofilter > 0 && tfd != -1) 1461 unlink(tfile); 1462 exit(0); 1463} 1464 1465static void 1466init(struct printer *pp) 1467{ 1468 char *s; 1469 1470 sprintf(&width[2], "%ld", pp->page_width); 1471 sprintf(&length[2], "%ld", pp->page_length); 1472 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1473 sprintf(&pxlength[2], "%ld", pp->page_plength); 1474 if ((s = checkremote(pp)) != 0) { 1475 syslog(LOG_WARNING, "%s", s); 1476 free(s); 1477 } 1478} 1479 1480void 1481startprinting(const char *printer) 1482{ 1483 struct printer myprinter, *pp = &myprinter; 1484 int status; 1485 1486 init_printer(pp); 1487 status = getprintcap(printer, pp); 1488 switch(status) { 1489 case PCAPERR_OSERR: 1490 syslog(LOG_ERR, "can't open printer description file: %m"); 1491 exit(1); 1492 case PCAPERR_NOTFOUND: 1493 syslog(LOG_ERR, "unknown printer: %s", printer); 1494 exit(1); 1495 case PCAPERR_TCLOOP: 1496 fatal(pp, "potential reference loop detected in printcap file"); 1497 default: 1498 break; 1499 } 1500 printjob(pp); 1501} 1502 1503/* 1504 * Acquire line printer or remote connection. 1505 */ 1506static void 1507openpr(const struct printer *pp) 1508{ 1509 int p[2]; 1510 char *cp; 1511 1512 if (pp->remote) { 1513 openrem(pp); 1514 } else if (*pp->lp) { 1515 if ((cp = strchr(pp->lp, '@')) != NULL) 1516 opennet(pp); 1517 else 1518 opentty(pp); 1519 } else { 1520 syslog(LOG_ERR, "%s: no line printer device or host name", 1521 pp->printer); 1522 exit(1); 1523 } 1524 1525 /* 1526 * Start up an output filter, if needed. 1527 */ 1528 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1529 pipe(p); 1530 if (pp->remote) { 1531 strcpy(tfile, TFILENAME); 1532 tfd = mkstemp(tfile); 1533 } 1534 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1535 dup2(p[0], 0); /* pipe is std in */ 1536 /* tfile/printer is stdout */ 1537 dup2(pp->remote ? tfd : pfd, 1); 1538 closelog(); 1539 closeallfds(3); 1540 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1541 cp = pp->filters[LPF_OUTPUT]; 1542 else 1543 cp++; 1544 execl(pp->filters[LPF_OUTPUT], cp, width, length, 1545 (char *)0); 1546 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1547 pp->filters[LPF_OUTPUT]); 1548 exit(1); 1549 } 1550 (void) close(p[0]); /* close input side */ 1551 ofd = p[1]; /* use pipe for output */ 1552 } else { 1553 ofd = pfd; 1554 ofilter = 0; 1555 } 1556} 1557 1558/* 1559 * Printer connected directly to the network 1560 * or to a terminal server on the net 1561 */ 1562static void 1563opennet(const struct printer *pp) 1564{ 1565 register int i; 1566 int resp; 1567 u_long port; 1568 char *ep; 1569 void (*savealrm)(int); 1570 1571 port = strtoul(pp->lp, &ep, 0); 1572 if (*ep != '@' || port > 65535) { 1573 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1574 pp->lp); 1575 exit(1); 1576 } 1577 ep++; 1578 1579 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1580 resp = -1; 1581 savealrm = signal(SIGALRM, alarmhandler); 1582 alarm(pp->conn_timeout); 1583 pfd = getport(pp, ep, port); 1584 alarm(0); 1585 (void)signal(SIGALRM, savealrm); 1586 if (pfd < 0 && errno == ECONNREFUSED) 1587 resp = 1; 1588 else if (pfd >= 0) { 1589 /* 1590 * need to delay a bit for rs232 lines 1591 * to stabilize in case printer is 1592 * connected via a terminal server 1593 */ 1594 delay(500); 1595 break; 1596 } 1597 if (i == 1) { 1598 if (resp < 0) 1599 pstatus(pp, "waiting for %s to come up", 1600 pp->lp); 1601 else 1602 pstatus(pp, 1603 "waiting for access to printer on %s", 1604 pp->lp); 1605 } 1606 sleep(i); 1607 } 1608 pstatus(pp, "sending to %s port %d", ep, port); 1609} 1610 1611/* 1612 * Printer is connected to an RS232 port on this host 1613 */ 1614static void 1615opentty(const struct printer *pp) 1616{ 1617 register int i; 1618 1619 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1620 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1621 if (pfd >= 0) { 1622 delay(500); 1623 break; 1624 } 1625 if (errno == ENOENT) { 1626 syslog(LOG_ERR, "%s: %m", pp->lp); 1627 exit(1); 1628 } 1629 if (i == 1) 1630 pstatus(pp, 1631 "waiting for %s to become ready (offline?)", 1632 pp->printer); 1633 sleep(i); 1634 } 1635 if (isatty(pfd)) 1636 setty(pp); 1637 pstatus(pp, "%s is ready and printing", pp->printer); 1638} 1639 1640/* 1641 * Printer is on a remote host 1642 */ 1643static void 1644openrem(const struct printer *pp) 1645{ 1646 register int i; 1647 int resp; 1648 void (*savealrm)(int); 1649 1650 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1651 resp = -1; 1652 savealrm = signal(SIGALRM, alarmhandler); 1653 alarm(pp->conn_timeout); 1654 pfd = getport(pp, pp->remote_host, 0); 1655 alarm(0); 1656 (void)signal(SIGALRM, savealrm); 1657 if (pfd >= 0) { 1658 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1659 (char *)0) 1660 == 2 + strlen(pp->remote_queue)) 1661 && (resp = response(pp)) == 0) 1662 break; 1663 (void) close(pfd); 1664 } 1665 if (i == 1) { 1666 if (resp < 0) 1667 pstatus(pp, "waiting for %s to come up", 1668 pp->remote_host); 1669 else { 1670 pstatus(pp, 1671 "waiting for queue to be enabled on %s", 1672 pp->remote_host); 1673 i = 256; 1674 } 1675 } 1676 sleep(i); 1677 } 1678 pstatus(pp, "sending to %s", pp->remote_host); 1679} 1680 1681/* 1682 * setup tty lines. 1683 */ 1684static void 1685setty(const struct printer *pp) 1686{ 1687 struct termios ttybuf; 1688 1689 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1690 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1691 exit(1); 1692 } 1693 if (tcgetattr(pfd, &ttybuf) < 0) { 1694 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1695 exit(1); 1696 } 1697 if (pp->baud_rate > 0) 1698 cfsetspeed(&ttybuf, pp->baud_rate); 1699 if (pp->mode_set) { 1700 char *s = strdup(pp->mode_set), *tmp; 1701 1702 while ((tmp = strsep(&s, ",")) != NULL) { 1703 (void) msearch(tmp, &ttybuf); 1704 } 1705 } 1706 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1707 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1708 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1709 } 1710 } 1711} 1712 1713#ifdef __STDC__ 1714#include <stdarg.h> 1715#else 1716#include <varargs.h> 1717#endif 1718 1719static void 1720#ifdef __STDC__ 1721pstatus(const struct printer *pp, const char *msg, ...) 1722#else 1723pstatus(pp, msg, va_alist) 1724 const struct printer *pp; 1725 char *msg; 1726 va_dcl 1727#endif 1728{ 1729 int fd; 1730 char *buf; 1731 va_list ap; 1732#ifdef __STDC__ 1733 va_start(ap, msg); 1734#else 1735 va_start(ap); 1736#endif 1737 1738 umask(0); 1739 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1740 if (fd < 0) { 1741 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1742 exit(1); 1743 } 1744 ftruncate(fd, 0); 1745 vasprintf(&buf, msg, ap); 1746 va_end(ap); 1747 writel(fd, buf, "\n", (char *)0); 1748 close(fd); 1749 free(buf); 1750} 1751 1752void 1753alarmhandler(int signo __unused) 1754{ 1755 /* the signal is ignored */ 1756 /* (the '__unused' is just to avoid a compile-time warning) */ 1757} 1758