printjob.c revision 95293
1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#ifndef lint 36static const char copyright[] = 37"@(#) Copyright (c) 1983, 1993\n\ 38 The Regents of the University of California. All rights reserved.\n"; 39#endif /* not lint */ 40 41#ifndef lint 42/* 43static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 44*/ 45static const char rcsid[] = 46 "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 95293 2002-04-23 00:06:10Z gad $"; 47#endif /* not lint */ 48 49 50/* 51 * printjob -- print jobs in the queue. 52 * 53 * NOTE: the lock file is used to pass information to lpq and lprm. 54 * it does not need to be removed because file locks are dynamic. 55 */ 56 57#include <sys/param.h> 58#include <sys/wait.h> 59#include <sys/stat.h> 60#include <sys/types.h> 61 62#include <pwd.h> 63#include <unistd.h> 64#include <signal.h> 65#include <syslog.h> 66#include <fcntl.h> 67#include <dirent.h> 68#include <errno.h> 69#include <stdio.h> 70#include <string.h> 71#include <stdlib.h> 72#include <sys/ioctl.h> 73#include <termios.h> 74#include <time.h> 75#include "lp.h" 76#include "lp.local.h" 77#include "pathnames.h" 78#include "extern.h" 79 80#define DORETURN 0 /* dofork should return "can't fork" error */ 81#define DOABORT 1 /* dofork should just die if fork() fails */ 82 83/* 84 * Error tokens 85 */ 86#define REPRINT -2 87#define ERROR -1 88#define OK 0 89#define FATALERR 1 90#define NOACCT 2 91#define FILTERERR 3 92#define ACCESS 4 93 94static dev_t fdev; /* device of file pointed to by symlink */ 95static ino_t fino; /* inode of file pointed to by symlink */ 96static FILE *cfp; /* control file */ 97static int child; /* id of any filters */ 98static int job_dfcnt; /* count of datafiles in current user job */ 99static int lfd; /* lock file descriptor */ 100static int ofd; /* output filter file descriptor */ 101static int ofilter; /* id of output filter, if any */ 102static int tfd = -1; /* output filter temp file output */ 103static int pfd; /* prstatic inter file descriptor */ 104static int pid; /* pid of lpd process */ 105static int prchild; /* id of pr process */ 106static char title[80]; /* ``pr'' title */ 107static char locale[80]; /* ``pr'' locale */ 108 109/* these two are set from pp->daemon_user, but only if they are needed */ 110static char *daemon_uname; /* set from pwd->pw_name */ 111static int daemon_defgid; 112 113static char class[32]; /* classification field */ 114static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */ 115 /* indentation size in static characters */ 116static char indent[10] = "-i0"; 117static char jobname[100]; /* job or file name */ 118static char length[10] = "-l"; /* page length in lines */ 119static char logname[32]; /* user's login name */ 120static char pxlength[10] = "-y"; /* page length in pixels */ 121static char pxwidth[10] = "-x"; /* page width in pixels */ 122/* tempstderr is the filename used to catch stderr from exec-ing filters */ 123static char tempstderr[] = "errs.XXXXXXX"; 124static char width[10] = "-w"; /* page width in static characters */ 125#define TFILENAME "fltXXXXXX" 126static char tfile[] = TFILENAME; /* file name for filter output */ 127 128static void abortpr(int _signo); 129static void alarmhandler(int _signo); 130static void banner(struct printer *_pp, char *_name1, char *_name2); 131static int dofork(const struct printer *_pp, int _action); 132static int dropit(int _c); 133static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av, 134 int _infd, int _outfd); 135static void init(struct printer *_pp); 136static void openpr(const struct printer *_pp); 137static void opennet(const struct printer *_pp); 138static void opentty(const struct printer *_pp); 139static void openrem(const struct printer *pp); 140static int print(struct printer *_pp, int _format, char *_file); 141static int printit(struct printer *_pp, char *_file); 142static void pstatus(const struct printer *_pp, const char *_msg, ...) 143 __printflike(2, 3); 144static char response(const struct printer *_pp); 145static void scan_out(struct printer *_pp, int _scfd, char *_scsp, 146 int _dlm); 147static char *scnline(int _key, char *_p, int _c); 148static int sendfile(struct printer *_pp, int _type, char *_file, 149 char _format, int _copyreq); 150static int sendit(struct printer *_pp, char *_file); 151static void sendmail(struct printer *_pp, char *_userid, int _bombed); 152static void setty(const struct printer *_pp); 153 154void 155printjob(struct printer *pp) 156{ 157 struct stat stb; 158 register struct jobqueue *q, **qp; 159 struct jobqueue **queue; 160 register int i, nitems; 161 off_t pidoff; 162 int errcnt, jobcount, tempfd; 163 164 jobcount = 0; 165 init(pp); /* set up capabilities */ 166 (void) write(1, "", 1); /* ack that daemon is started */ 167 (void) close(2); /* set up log file */ 168 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 169 syslog(LOG_ERR, "%s: %m", pp->log_file); 170 (void) open(_PATH_DEVNULL, O_WRONLY); 171 } 172 setgid(getegid()); 173 pid = getpid(); /* for use with lprm */ 174 setpgrp(0, pid); 175 176 /* 177 * At initial lpd startup, printjob may be called with various 178 * signal handlers in effect. After that initial startup, any 179 * calls to printjob will have a *different* set of signal-handlers 180 * in effect. Make sure all handlers are the ones we want. 181 */ 182 signal(SIGCHLD, SIG_DFL); 183 signal(SIGHUP, abortpr); 184 signal(SIGINT, abortpr); 185 signal(SIGQUIT, abortpr); 186 signal(SIGTERM, abortpr); 187 188 /* 189 * uses short form file names 190 */ 191 if (chdir(pp->spool_dir) < 0) { 192 syslog(LOG_ERR, "%s: %m", pp->spool_dir); 193 exit(1); 194 } 195 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 196 exit(0); /* printing disabled */ 197 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 198 LOCK_FILE_MODE); 199 if (lfd < 0) { 200 if (errno == EWOULDBLOCK) /* active daemon present */ 201 exit(0); 202 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 203 exit(1); 204 } 205 /* turn off non-blocking mode (was turned on for lock effects only) */ 206 if (fcntl(lfd, F_SETFL, 0) < 0) { 207 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 208 exit(1); 209 } 210 ftruncate(lfd, 0); 211 /* 212 * write process id for others to know 213 */ 214 sprintf(line, "%u\n", pid); 215 pidoff = i = strlen(line); 216 if (write(lfd, line, i) != i) { 217 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 218 exit(1); 219 } 220 /* 221 * search the spool directory for work and sort by queue order. 222 */ 223 if ((nitems = getq(pp, &queue)) < 0) { 224 syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 225 pp->spool_dir); 226 exit(1); 227 } 228 if (nitems == 0) /* no work to do */ 229 exit(0); 230 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 231 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 232 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 233 pp->lock_file); 234 } 235 236 /* create a file which will be used to hold stderr from filters */ 237 if ((tempfd = mkstemp(tempstderr)) == -1) { 238 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 239 tempstderr); 240 exit(1); 241 } 242 if ((i = fchmod(tempfd, 0664)) == -1) { 243 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 244 tempstderr); 245 exit(1); 246 } 247 /* lpd doesn't need it to be open, it just needs it to exist */ 248 close(tempfd); 249 250 openpr(pp); /* open printer or remote */ 251again: 252 /* 253 * we found something to do now do it -- 254 * write the name of the current control file into the lock file 255 * so the spool queue program can tell what we're working on 256 */ 257 for (qp = queue; nitems--; free((char *) q)) { 258 q = *qp++; 259 if (stat(q->job_cfname, &stb) < 0) 260 continue; 261 errcnt = 0; 262 restart: 263 (void) lseek(lfd, pidoff, 0); 264 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 265 i = strlen(line); 266 if (write(lfd, line, i) != i) 267 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 268 pp->lock_file); 269 if (!pp->remote) 270 i = printit(pp, q->job_cfname); 271 else 272 i = sendit(pp, q->job_cfname); 273 /* 274 * Check to see if we are supposed to stop printing or 275 * if we are to rebuild the queue. 276 */ 277 if (fstat(lfd, &stb) == 0) { 278 /* stop printing before starting next job? */ 279 if (stb.st_mode & LFM_PRINT_DIS) 280 goto done; 281 /* rebuild queue (after lpc topq) */ 282 if (stb.st_mode & LFM_RESET_QUE) { 283 for (free(q); nitems--; free(q)) 284 q = *qp++; 285 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 286 < 0) 287 syslog(LOG_WARNING, "%s: %s: %m", 288 pp->printer, pp->lock_file); 289 break; 290 } 291 } 292 if (i == OK) /* all files of this job printed */ 293 jobcount++; 294 else if (i == REPRINT && ++errcnt < 5) { 295 /* try reprinting the job */ 296 syslog(LOG_INFO, "restarting %s", pp->printer); 297 if (ofilter > 0) { 298 kill(ofilter, SIGCONT); /* to be sure */ 299 (void) close(ofd); 300 while ((i = wait(NULL)) > 0 && i != ofilter) 301 ; 302 if (i < 0) 303 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m", 304 pp->printer, ofilter); 305 ofilter = 0; 306 } 307 (void) close(pfd); /* close printer */ 308 if (ftruncate(lfd, pidoff) < 0) 309 syslog(LOG_WARNING, "%s: %s: %m", 310 pp->printer, pp->lock_file); 311 openpr(pp); /* try to reopen printer */ 312 goto restart; 313 } else { 314 syslog(LOG_WARNING, "%s: job could not be %s (%s)", 315 pp->printer, 316 pp->remote ? "sent to remote host" : "printed", 317 q->job_cfname); 318 if (i == REPRINT) { 319 /* ensure we don't attempt this job again */ 320 (void) unlink(q->job_cfname); 321 q->job_cfname[0] = 'd'; 322 (void) unlink(q->job_cfname); 323 if (logname[0]) 324 sendmail(pp, logname, FATALERR); 325 } 326 } 327 } 328 free(queue); 329 /* 330 * search the spool directory for more work. 331 */ 332 if ((nitems = getq(pp, &queue)) < 0) { 333 syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 334 pp->spool_dir); 335 exit(1); 336 } 337 if (nitems == 0) { /* no more work to do */ 338 done: 339 if (jobcount > 0) { /* jobs actually printed */ 340 if (!pp->no_formfeed && !pp->tof) 341 (void) write(ofd, pp->form_feed, 342 strlen(pp->form_feed)); 343 if (pp->trailer != NULL) /* output trailer */ 344 (void) write(ofd, pp->trailer, 345 strlen(pp->trailer)); 346 } 347 (void) close(ofd); 348 (void) wait(NULL); 349 (void) unlink(tempstderr); 350 exit(0); 351 } 352 goto again; 353} 354 355char fonts[4][50]; /* fonts for troff */ 356 357char ifonts[4][40] = { 358 _PATH_VFONTR, 359 _PATH_VFONTI, 360 _PATH_VFONTB, 361 _PATH_VFONTS, 362}; 363 364/* 365 * The remaining part is the reading of the control file (cf) 366 * and performing the various actions. 367 */ 368static int 369printit(struct printer *pp, char *file) 370{ 371 register int i; 372 char *cp; 373 int bombed, didignorehdr; 374 375 bombed = OK; 376 didignorehdr = 0; 377 /* 378 * open control file; ignore if no longer there. 379 */ 380 if ((cfp = fopen(file, "r")) == NULL) { 381 syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 382 return(OK); 383 } 384 /* 385 * Reset troff fonts. 386 */ 387 for (i = 0; i < 4; i++) 388 strcpy(fonts[i], ifonts[i]); 389 sprintf(&width[2], "%ld", pp->page_width); 390 strcpy(indent+2, "0"); 391 392 /* initialize job-specific count of datafiles processed */ 393 job_dfcnt = 0; 394 395 /* 396 * read the control file for work to do 397 * 398 * file format -- first character in the line is a command 399 * rest of the line is the argument. 400 * valid commands are: 401 * 402 * S -- "stat info" for symbolic link protection 403 * J -- "job name" on banner page 404 * C -- "class name" on banner page 405 * L -- "literal" user's name to print on banner 406 * T -- "title" for pr 407 * H -- "host name" of machine where lpr was done 408 * P -- "person" user's login name 409 * I -- "indent" amount to indent output 410 * R -- laser dpi "resolution" 411 * f -- "file name" name of text file to print 412 * l -- "file name" text file with control chars 413 * o -- "file name" postscript file, according to 414 * the RFC. Here it is treated like an 'f'. 415 * p -- "file name" text file to print with pr(1) 416 * t -- "file name" troff(1) file to print 417 * n -- "file name" ditroff(1) file to print 418 * d -- "file name" dvi file to print 419 * g -- "file name" plot(1G) file to print 420 * v -- "file name" plain raster file to print 421 * c -- "file name" cifplot file to print 422 * 1 -- "R font file" for troff 423 * 2 -- "I font file" for troff 424 * 3 -- "B font file" for troff 425 * 4 -- "S font file" for troff 426 * N -- "name" of file (used by lpq) 427 * U -- "unlink" name of file to remove 428 * (after we print it. (Pass 2 only)). 429 * M -- "mail" to user when done printing 430 * Z -- "locale" for pr 431 * 432 * getline reads a line and expands tabs to blanks 433 */ 434 435 /* pass 1 */ 436 437 while (getline(cfp)) 438 switch (line[0]) { 439 case 'H': 440 strlcpy(origin_host, line + 1, sizeof(origin_host)); 441 if (class[0] == '\0') { 442 strlcpy(class, line+1, sizeof(class)); 443 } 444 continue; 445 446 case 'P': 447 strlcpy(logname, line + 1, sizeof(logname)); 448 if (pp->restricted) { /* restricted */ 449 if (getpwnam(logname) == NULL) { 450 bombed = NOACCT; 451 sendmail(pp, line+1, bombed); 452 goto pass2; 453 } 454 } 455 continue; 456 457 case 'S': 458 cp = line+1; 459 i = 0; 460 while (*cp >= '0' && *cp <= '9') 461 i = i * 10 + (*cp++ - '0'); 462 fdev = i; 463 cp++; 464 i = 0; 465 while (*cp >= '0' && *cp <= '9') 466 i = i * 10 + (*cp++ - '0'); 467 fino = i; 468 continue; 469 470 case 'J': 471 if (line[1] != '\0') { 472 strlcpy(jobname, line + 1, sizeof(jobname)); 473 } else 474 strcpy(jobname, " "); 475 continue; 476 477 case 'C': 478 if (line[1] != '\0') 479 strlcpy(class, line + 1, sizeof(class)); 480 else if (class[0] == '\0') { 481 /* XXX - why call gethostname instead of 482 * just strlcpy'ing local_host? */ 483 gethostname(class, sizeof(class)); 484 class[sizeof(class) - 1] = '\0'; 485 } 486 continue; 487 488 case 'T': /* header title for pr */ 489 strlcpy(title, line + 1, sizeof(title)); 490 continue; 491 492 case 'L': /* identification line */ 493 if (!pp->no_header && !pp->header_last) 494 banner(pp, line+1, jobname); 495 continue; 496 497 case '1': /* troff fonts */ 498 case '2': 499 case '3': 500 case '4': 501 if (line[1] != '\0') { 502 strlcpy(fonts[line[0]-'1'], line + 1, 503 (size_t)50); 504 } 505 continue; 506 507 case 'W': /* page width */ 508 strlcpy(width+2, line + 1, sizeof(width) - 2); 509 continue; 510 511 case 'I': /* indent amount */ 512 strlcpy(indent+2, line + 1, sizeof(indent) - 2); 513 continue; 514 515 case 'Z': /* locale for pr */ 516 strlcpy(locale, line + 1, sizeof(locale)); 517 continue; 518 519 default: /* some file to print */ 520 /* only lowercase cmd-codes include a file-to-print */ 521 if ((line[0] < 'a') || (line[0] > 'z')) { 522 /* ignore any other lines */ 523 if (lflag <= 1) 524 continue; 525 if (!didignorehdr) { 526 syslog(LOG_INFO, "%s: in %s :", 527 pp->printer, file); 528 didignorehdr = 1; 529 } 530 syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 531 pp->printer, line[0], &line[1]); 532 continue; 533 } 534 i = print(pp, line[0], line+1); 535 switch (i) { 536 case ERROR: 537 if (bombed == OK) 538 bombed = FATALERR; 539 break; 540 case REPRINT: 541 (void) fclose(cfp); 542 return(REPRINT); 543 case FILTERERR: 544 case ACCESS: 545 bombed = i; 546 sendmail(pp, logname, bombed); 547 } 548 title[0] = '\0'; 549 continue; 550 551 case 'N': 552 case 'U': 553 case 'M': 554 case 'R': 555 continue; 556 } 557 558 /* pass 2 */ 559 560pass2: 561 fseek(cfp, 0L, 0); 562 while (getline(cfp)) 563 switch (line[0]) { 564 case 'L': /* identification line */ 565 if (!pp->no_header && pp->header_last) 566 banner(pp, line+1, jobname); 567 continue; 568 569 case 'M': 570 if (bombed < NOACCT) /* already sent if >= NOACCT */ 571 sendmail(pp, line+1, bombed); 572 continue; 573 574 case 'U': 575 if (strchr(line+1, '/')) 576 continue; 577 (void) unlink(line+1); 578 } 579 /* 580 * clean-up in case another control file exists 581 */ 582 (void) fclose(cfp); 583 (void) unlink(file); 584 return(bombed == OK ? OK : ERROR); 585} 586 587/* 588 * Print a file. 589 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 590 * Return -1 if a non-recoverable error occured, 591 * 2 if the filter detected some errors (but printed the job anyway), 592 * 1 if we should try to reprint this job and 593 * 0 if all is well. 594 * Note: all filters take stdin as the file, stdout as the printer, 595 * stderr as the log file, and must not ignore SIGINT. 596 */ 597static int 598print(struct printer *pp, int format, char *file) 599{ 600 register int n, i; 601 register char *prog; 602 int fi, fo; 603 FILE *fp; 604 char *av[15], buf[BUFSIZ]; 605 int pid, p[2], stopped; 606 union wait status; 607 struct stat stb; 608 609 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 610 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 611 pp->printer, file, format); 612 return(ERROR); 613 } 614 /* 615 * Check to see if data file is a symbolic link. If so, it should 616 * still point to the same file or someone is trying to print 617 * something he shouldn't. 618 */ 619 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 620 (stb.st_dev != fdev || stb.st_ino != fino)) 621 return(ACCESS); 622 623 job_dfcnt++; /* increment datafile counter for this job */ 624 stopped = 0; /* output filter is not stopped */ 625 626 /* everything seems OK, start it up */ 627 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 628 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 629 pp->tof = 1; 630 } 631 if (pp->filters[LPF_INPUT] == NULL 632 && (format == 'f' || format == 'l' || format == 'o')) { 633 pp->tof = 0; 634 while ((n = read(fi, buf, BUFSIZ)) > 0) 635 if (write(ofd, buf, n) != n) { 636 (void) close(fi); 637 return(REPRINT); 638 } 639 (void) close(fi); 640 return(OK); 641 } 642 switch (format) { 643 case 'p': /* print file using 'pr' */ 644 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 645 prog = _PATH_PR; 646 i = 0; 647 av[i++] = "pr"; 648 av[i++] = width; 649 av[i++] = length; 650 av[i++] = "-h"; 651 av[i++] = *title ? title : " "; 652 av[i++] = "-L"; 653 av[i++] = *locale ? locale : "C"; 654 av[i++] = "-F"; 655 av[i] = 0; 656 fo = ofd; 657 goto start; 658 } 659 pipe(p); 660 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 661 dup2(fi, 0); /* file is stdin */ 662 dup2(p[1], 1); /* pipe is stdout */ 663 closelog(); 664 closeallfds(3); 665 execl(_PATH_PR, "pr", width, length, 666 "-h", *title ? title : " ", 667 "-L", *locale ? locale : "C", 668 "-F", (char *)0); 669 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 670 exit(2); 671 } 672 (void) close(p[1]); /* close output side */ 673 (void) close(fi); 674 if (prchild < 0) { 675 prchild = 0; 676 (void) close(p[0]); 677 return(ERROR); 678 } 679 fi = p[0]; /* use pipe for input */ 680 case 'f': /* print plain text file */ 681 prog = pp->filters[LPF_INPUT]; 682 av[1] = width; 683 av[2] = length; 684 av[3] = indent; 685 n = 4; 686 break; 687 case 'o': /* print postscript file */ 688 /* 689 * Treat this as a "plain file with control characters", and 690 * assume the standard LPF_INPUT filter will recognize that 691 * the data is postscript and know what to do with it. These 692 * 'o'-file requests could come from MacOS 10.1 systems. 693 * (later versions of MacOS 10 will explicitly use 'l') 694 * A postscript file can contain binary data, which is why 'l' 695 * is somewhat more appropriate than 'f'. 696 */ 697 /* FALLTHROUGH */ 698 case 'l': /* like 'f' but pass control characters */ 699 prog = pp->filters[LPF_INPUT]; 700 av[1] = "-c"; 701 av[2] = width; 702 av[3] = length; 703 av[4] = indent; 704 n = 5; 705 break; 706 case 'r': /* print a fortran text file */ 707 prog = pp->filters[LPF_FORTRAN]; 708 av[1] = width; 709 av[2] = length; 710 n = 3; 711 break; 712 case 't': /* print troff output */ 713 case 'n': /* print ditroff output */ 714 case 'd': /* print tex output */ 715 (void) unlink(".railmag"); 716 if ((fo = creat(".railmag", FILMOD)) < 0) { 717 syslog(LOG_ERR, "%s: cannot create .railmag", 718 pp->printer); 719 (void) unlink(".railmag"); 720 } else { 721 for (n = 0; n < 4; n++) { 722 if (fonts[n][0] != '/') 723 (void) write(fo, _PATH_VFONT, 724 sizeof(_PATH_VFONT) - 1); 725 (void) write(fo, fonts[n], strlen(fonts[n])); 726 (void) write(fo, "\n", 1); 727 } 728 (void) close(fo); 729 } 730 prog = (format == 't') ? pp->filters[LPF_TROFF] 731 : ((format == 'n') ? pp->filters[LPF_DITROFF] 732 : pp->filters[LPF_DVI]); 733 av[1] = pxwidth; 734 av[2] = pxlength; 735 n = 3; 736 break; 737 case 'c': /* print cifplot output */ 738 prog = pp->filters[LPF_CIFPLOT]; 739 av[1] = pxwidth; 740 av[2] = pxlength; 741 n = 3; 742 break; 743 case 'g': /* print plot(1G) output */ 744 prog = pp->filters[LPF_GRAPH]; 745 av[1] = pxwidth; 746 av[2] = pxlength; 747 n = 3; 748 break; 749 case 'v': /* print raster output */ 750 prog = pp->filters[LPF_RASTER]; 751 av[1] = pxwidth; 752 av[2] = pxlength; 753 n = 3; 754 break; 755 default: 756 (void) close(fi); 757 syslog(LOG_ERR, "%s: illegal format character '%c'", 758 pp->printer, format); 759 return(ERROR); 760 } 761 if (prog == NULL) { 762 (void) close(fi); 763 syslog(LOG_ERR, 764 "%s: no filter found in printcap for format character '%c'", 765 pp->printer, format); 766 return(ERROR); 767 } 768 if ((av[0] = strrchr(prog, '/')) != NULL) 769 av[0]++; 770 else 771 av[0] = prog; 772 av[n++] = "-n"; 773 av[n++] = logname; 774 av[n++] = "-h"; 775 av[n++] = origin_host; 776 av[n++] = pp->acct_file; 777 av[n] = 0; 778 fo = pfd; 779 if (ofilter > 0) { /* stop output filter */ 780 write(ofd, "\031\1", 2); 781 while ((pid = 782 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 783 ; 784 if (pid < 0) 785 syslog(LOG_WARNING, "%s: after stopping 'of', wait3() returned: %m", 786 pp->printer); 787 else if (status.w_stopval != WSTOPPED) { 788 (void) close(fi); 789 syslog(LOG_WARNING, 790 "%s: output filter died " 791 "(pid=%d retcode=%d termsig=%d)", 792 pp->printer, ofilter, status.w_retcode, 793 status.w_termsig); 794 return(REPRINT); 795 } 796 stopped++; 797 } 798start: 799 if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 800 dup2(fi, 0); 801 dup2(fo, 1); 802 /* setup stderr for the filter (child process) 803 * so it goes to our temporary errors file */ 804 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 805 if (n >= 0) 806 dup2(n, 2); 807 closelog(); 808 closeallfds(3); 809 execv(prog, av); 810 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, 811 prog); 812 exit(2); 813 } 814 (void) close(fi); 815 if (child < 0) 816 status.w_retcode = 100; 817 else { 818 while ((pid = wait((int *)&status)) > 0 && pid != child) 819 ; 820 if (pid < 0) { 821 status.w_retcode = 100; 822 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m", 823 pp->printer, prog); 824 } 825 } 826 child = 0; 827 prchild = 0; 828 if (stopped) { /* restart output filter */ 829 if (kill(ofilter, SIGCONT) < 0) { 830 syslog(LOG_ERR, "cannot restart output filter"); 831 exit(1); 832 } 833 } 834 pp->tof = 0; 835 836 /* Copy the filter's output to "lf" logfile */ 837 if ((fp = fopen(tempstderr, "r"))) { 838 while (fgets(buf, sizeof(buf), fp)) 839 fputs(buf, stderr); 840 fclose(fp); 841 } 842 843 if (!WIFEXITED(status)) { 844 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 845 pp->printer, format, status.w_termsig); 846 return(ERROR); 847 } 848 switch (status.w_retcode) { 849 case 0: 850 pp->tof = 1; 851 return(OK); 852 case 1: 853 return(REPRINT); 854 case 2: 855 return(ERROR); 856 default: 857 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 858 pp->printer, format, status.w_retcode); 859 return(FILTERERR); 860 } 861} 862 863/* 864 * Send the daemon control file (cf) and any data files. 865 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 866 * 0 if all is well. 867 */ 868static int 869sendit(struct printer *pp, char *file) 870{ 871 int dfcopies, err, i; 872 char *cp, last[BUFSIZ]; 873 874 /* 875 * open control file 876 */ 877 if ((cfp = fopen(file, "r")) == NULL) 878 return(OK); 879 880 /* initialize job-specific count of datafiles processed */ 881 job_dfcnt = 0; 882 883 /* 884 * read the control file for work to do 885 * 886 * file format -- first character in the line is a command 887 * rest of the line is the argument. 888 * commands of interest are: 889 * 890 * a-z -- "file name" name of file to print 891 * U -- "unlink" name of file to remove 892 * (after we print it. (Pass 2 only)). 893 */ 894 895 /* 896 * pass 1 897 */ 898 err = OK; 899 while (getline(cfp)) { 900 again: 901 if (line[0] == 'S') { 902 cp = line+1; 903 i = 0; 904 while (*cp >= '0' && *cp <= '9') 905 i = i * 10 + (*cp++ - '0'); 906 fdev = i; 907 cp++; 908 i = 0; 909 while (*cp >= '0' && *cp <= '9') 910 i = i * 10 + (*cp++ - '0'); 911 fino = i; 912 } else if (line[0] == 'H') { 913 strlcpy(origin_host, line + 1, sizeof(origin_host)); 914 if (class[0] == '\0') { 915 strlcpy(class, line + 1, sizeof(class)); 916 } 917 } else if (line[0] == 'P') { 918 strlcpy(logname, line + 1, sizeof(logname)); 919 if (pp->restricted) { /* restricted */ 920 if (getpwnam(logname) == NULL) { 921 sendmail(pp, line+1, NOACCT); 922 err = ERROR; 923 break; 924 } 925 } 926 } else if (line[0] == 'I') { 927 strlcpy(indent+2, line + 1, sizeof(indent) - 2); 928 } else if (line[0] >= 'a' && line[0] <= 'z') { 929 dfcopies = 1; 930 strcpy(last, line); 931 while ((i = getline(cfp)) != 0) { 932 if (strcmp(last, line) != 0) 933 break; 934 dfcopies++; 935 } 936 switch (sendfile(pp, '\3', last+1, *last, dfcopies)) { 937 case OK: 938 if (i) 939 goto again; 940 break; 941 case REPRINT: 942 (void) fclose(cfp); 943 return(REPRINT); 944 case ACCESS: 945 sendmail(pp, logname, ACCESS); 946 case ERROR: 947 err = ERROR; 948 } 949 break; 950 } 951 } 952 if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) { 953 (void) fclose(cfp); 954 return(REPRINT); 955 } 956 /* 957 * pass 2 958 */ 959 fseek(cfp, 0L, 0); 960 while (getline(cfp)) 961 if (line[0] == 'U' && !strchr(line+1, '/')) 962 (void) unlink(line+1); 963 /* 964 * clean-up in case another control file exists 965 */ 966 (void) fclose(cfp); 967 (void) unlink(file); 968 return(err); 969} 970 971/* 972 * Send a data file to the remote machine and spool it. 973 * Return positive if we should try resending. 974 */ 975static int 976sendfile(struct printer *pp, int type, char *file, char format, int copyreq) 977{ 978 int i, amt; 979 struct stat stb; 980 char *av[15], *filtcmd; 981 char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4]; 982 int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc; 983 984 statrc = lstat(file, &stb); 985 if (statrc < 0) { 986 syslog(LOG_ERR, "%s: error from lstat(%s): %m", 987 pp->printer, file); 988 return (ERROR); 989 } 990 sfd = open(file, O_RDONLY); 991 if (sfd < 0) { 992 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m", 993 pp->printer, file); 994 return (ERROR); 995 } 996 /* 997 * Check to see if data file is a symbolic link. If so, it should 998 * still point to the same file or someone is trying to print something 999 * he shouldn't. 1000 */ 1001 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 && 1002 (stb.st_dev != fdev || stb.st_ino != fino)) { 1003 close(sfd); 1004 return (ACCESS); 1005 } 1006 1007 /* Everything seems OK for reading the file, now to send it */ 1008 filtcmd = NULL; 1009 sizerr = 0; 1010 tfd = -1; 1011 if (type == '\3') { 1012 /* 1013 * Type == 3 means this is a datafile, not a control file. 1014 * Increment the counter of data-files in this job, and 1015 * then check for input or output filters (which are only 1016 * applied to datafiles, not control files). 1017 */ 1018 job_dfcnt++; 1019 1020 /* 1021 * Note that here we are filtering datafiles, one at a time, 1022 * as they are sent to the remote machine. Here, the *only* 1023 * difference between an input filter (`if=') and an output 1024 * filter (`of=') is the argument list that the filter is 1025 * started up with. Here, the output filter is executed 1026 * for each individual file as it is sent. This is not the 1027 * same as local print queues, where the output filter is 1028 * started up once, and then all jobs are passed thru that 1029 * single invocation of the output filter. 1030 * 1031 * Also note that a queue for a remote-machine can have an 1032 * input filter or an output filter, but not both. 1033 */ 1034 if (pp->filters[LPF_INPUT]) { 1035 filtcmd = pp->filters[LPF_INPUT]; 1036 av[0] = filtcmd; 1037 narg = 0; 1038 strcpy(opt_c, "-c"); 1039 strcpy(opt_h, "-h"); 1040 strcpy(opt_n, "-n"); 1041 if (format == 'l') 1042 av[++narg] = opt_c; 1043 av[++narg] = width; 1044 av[++narg] = length; 1045 av[++narg] = indent; 1046 av[++narg] = opt_n; 1047 av[++narg] = logname; 1048 av[++narg] = opt_h; 1049 av[++narg] = origin_host; 1050 av[++narg] = pp->acct_file; 1051 av[++narg] = NULL; 1052 } else if (pp->filters[LPF_OUTPUT]) { 1053 filtcmd = pp->filters[LPF_OUTPUT]; 1054 av[0] = filtcmd; 1055 narg = 0; 1056 av[++narg] = width; 1057 av[++narg] = length; 1058 av[++narg] = NULL; 1059 } 1060 } 1061 if (filtcmd) { 1062 /* 1063 * If there is an input or output filter, we have to run 1064 * the datafile thru that filter and store the result as 1065 * a temporary spool file, because the protocol requires 1066 * that we send the remote host the file-size before we 1067 * start to send any of the data. 1068 */ 1069 strcpy(tfile, TFILENAME); 1070 tfd = mkstemp(tfile); 1071 if (tfd == -1) { 1072 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 1073 TFILENAME); 1074 sfres = ERROR; 1075 goto return_sfres; 1076 } 1077 filtstat = execfilter(pp, filtcmd, av, sfd, tfd); 1078 1079 /* process the return-code from the filter */ 1080 switch (filtstat) { 1081 case 0: 1082 break; 1083 case 1: 1084 sfres = REPRINT; 1085 goto return_sfres; 1086 case 2: 1087 sfres = ERROR; 1088 goto return_sfres; 1089 default: 1090 syslog(LOG_WARNING, 1091 "%s: filter '%c' exited (retcode=%d)", 1092 pp->printer, format, filtstat); 1093 sfres = FILTERERR; 1094 goto return_sfres; 1095 } 1096 statrc = fstat(tfd, &stb); /* to find size of tfile */ 1097 if (statrc < 0) { 1098 syslog(LOG_ERR, 1099 "%s: error processing 'if', fstat(%s): %m", 1100 pp->printer, tfile); 1101 sfres = ERROR; 1102 goto return_sfres; 1103 } 1104 close(sfd); 1105 sfd = tfd; 1106 lseek(sfd, 0, SEEK_SET); 1107 } 1108 1109 copycnt = 0; 1110sendagain: 1111 copycnt++; 1112 1113 if (copycnt < 2) 1114 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1115 else 1116 (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size, 1117 file, copycnt); 1118 amt = strlen(buf); 1119 for (i = 0; ; i++) { 1120 if (write(pfd, buf, amt) != amt || 1121 (resp = response(pp)) < 0 || resp == '\1') { 1122 sfres = REPRINT; 1123 goto return_sfres; 1124 } else if (resp == '\0') 1125 break; 1126 if (i == 0) 1127 pstatus(pp, 1128 "no space on remote; waiting for queue to drain"); 1129 if (i == 10) 1130 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1131 pp->printer, pp->remote_host); 1132 sleep(5 * 60); 1133 } 1134 if (i) 1135 pstatus(pp, "sending to %s", pp->remote_host); 1136 /* 1137 * XXX - we should change trstat_init()/trstat_write() to include 1138 * the copycnt in the statistics record it may write. 1139 */ 1140 if (type == '\3') 1141 trstat_init(pp, file, job_dfcnt); 1142 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1143 amt = BUFSIZ; 1144 if (i + amt > stb.st_size) 1145 amt = stb.st_size - i; 1146 if (sizerr == 0 && read(sfd, buf, amt) != amt) 1147 sizerr = 1; 1148 if (write(pfd, buf, amt) != amt) { 1149 sfres = REPRINT; 1150 goto return_sfres; 1151 } 1152 } 1153 1154 if (sizerr) { 1155 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1156 /* tell recvjob to ignore this file */ 1157 (void) write(pfd, "\1", 1); 1158 sfres = ERROR; 1159 goto return_sfres; 1160 } 1161 if (write(pfd, "", 1) != 1 || response(pp)) { 1162 sfres = REPRINT; 1163 goto return_sfres; 1164 } 1165 if (type == '\3') { 1166 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1167 pp->remote_host, origin_host); 1168 /* 1169 * Usually we only need to send one copy of a datafile, 1170 * because the control-file will simply print the same 1171 * file multiple times. However, some printers ignore 1172 * the control file, and simply print each data file as 1173 * it arrives. For such "remote hosts", we need to 1174 * transfer the same data file multiple times. Such a 1175 * a host is indicated by adding 'rc' to the printcap 1176 * entry. 1177 * XXX - Right now this ONLY works for remote hosts which 1178 * do ignore the name of the data file, because 1179 * this sends the file multiple times with slight 1180 * changes to the filename. To do this right would 1181 * require that we also rewrite the control file 1182 * to match those filenames. 1183 */ 1184 if (pp->resend_copies && (copycnt < copyreq)) { 1185 lseek(sfd, 0, SEEK_SET); 1186 goto sendagain; 1187 } 1188 } 1189 sfres = OK; 1190 1191return_sfres: 1192 (void)close(sfd); 1193 if (tfd != -1) { 1194 /* 1195 * If tfd is set, then it is the same value as sfd, and 1196 * therefore it is already closed at this point. All 1197 * we need to do is remove the temporary file. 1198 */ 1199 tfd = -1; 1200 unlink(tfile); 1201 } 1202 return (sfres); 1203} 1204 1205/* 1206 * This routine is called to execute one of the filters as was 1207 * specified in a printcap entry. While the child-process will read 1208 * all of 'infd', it is up to the caller to close that file descriptor 1209 * in the parent process. 1210 */ 1211static int 1212execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd) 1213{ 1214 int errfd, fpid, wpid; 1215 FILE *errfp; 1216 union wait status; /* XXX */ 1217 char buf[BUFSIZ], *slash; 1218 1219 fpid = dofork(pp, DORETURN); 1220 if (fpid != 0) { 1221 /* 1222 * This is the parent process, which just waits for the child 1223 * to complete and then returns the result. Note that it is 1224 * the child process which reads the input stream. 1225 */ 1226 if (fpid < 0) 1227 status.w_retcode = 100; 1228 else { 1229 while ((wpid = wait((int *)&status)) > 0 && 1230 wpid != fpid) 1231 ; 1232 if (wpid < 0) { 1233 status.w_retcode = 100; 1234 syslog(LOG_WARNING, 1235 "%s: after execv(%s), wait() returned: %m", 1236 pp->printer, f_cmd); 1237 } 1238 } 1239 1240 /* 1241 * Copy everything the filter wrote to stderr from our 1242 * temporary errors file to the "lf=" logfile. 1243 */ 1244 errfp = fopen(tempstderr, "r"); 1245 if (errfp) { 1246 while (fgets(buf, sizeof(buf), errfp)) 1247 fputs(buf, stderr); 1248 fclose(errfp); 1249 } 1250 1251 return (status.w_retcode); 1252 } 1253 1254 /* 1255 * This is the child process, which is the one that executes the 1256 * given filter. 1257 */ 1258 /* 1259 * If the first parameter has any slashes in it, then change it 1260 * to point to the first character after the last slash. 1261 */ 1262 slash = strrchr(f_av[0], '/'); 1263 if (slash != NULL) 1264 f_av[0] = slash + 1; 1265 /* 1266 * XXX - in the future, this should setup an explicit list of 1267 * environment variables and use execve()! 1268 */ 1269 1270 /* 1271 * Setup stdin, stdout, and stderr as we want them when the filter 1272 * is running. Stderr is setup so it points to a temporary errors 1273 * file, and the parent process will copy that temporary file to 1274 * the real logfile after the filter completes. 1275 */ 1276 dup2(infd, 0); 1277 dup2(outfd, 1); 1278 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1279 if (errfd >= 0) 1280 dup2(errfd, 2); 1281 closelog(); 1282 closeallfds(3); 1283 execv(f_cmd, f_av); 1284 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd); 1285 exit(2); 1286 /* NOTREACHED */ 1287} 1288 1289/* 1290 * Check to make sure there have been no errors and that both programs 1291 * are in sync with eachother. 1292 * Return non-zero if the connection was lost. 1293 */ 1294static char 1295response(const struct printer *pp) 1296{ 1297 char resp; 1298 1299 if (read(pfd, &resp, 1) != 1) { 1300 syslog(LOG_INFO, "%s: lost connection", pp->printer); 1301 return(-1); 1302 } 1303 return(resp); 1304} 1305 1306/* 1307 * Banner printing stuff 1308 */ 1309static void 1310banner(struct printer *pp, char *name1, char *name2) 1311{ 1312 time_t tvec; 1313 1314 time(&tvec); 1315 if (!pp->no_formfeed && !pp->tof) 1316 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1317 if (pp->short_banner) { /* short banner only */ 1318 if (class[0]) { 1319 (void) write(ofd, class, strlen(class)); 1320 (void) write(ofd, ":", 1); 1321 } 1322 (void) write(ofd, name1, strlen(name1)); 1323 (void) write(ofd, " Job: ", 7); 1324 (void) write(ofd, name2, strlen(name2)); 1325 (void) write(ofd, " Date: ", 8); 1326 (void) write(ofd, ctime(&tvec), 24); 1327 (void) write(ofd, "\n", 1); 1328 } else { /* normal banner */ 1329 (void) write(ofd, "\n\n\n", 3); 1330 scan_out(pp, ofd, name1, '\0'); 1331 (void) write(ofd, "\n\n", 2); 1332 scan_out(pp, ofd, name2, '\0'); 1333 if (class[0]) { 1334 (void) write(ofd,"\n\n\n",3); 1335 scan_out(pp, ofd, class, '\0'); 1336 } 1337 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1338 (void) write(ofd, name2, strlen(name2)); 1339 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1340 (void) write(ofd, ctime(&tvec), 24); 1341 (void) write(ofd, "\n", 1); 1342 } 1343 if (!pp->no_formfeed) 1344 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1345 pp->tof = 1; 1346} 1347 1348static char * 1349scnline(int key, char *p, int c) 1350{ 1351 register int scnwidth; 1352 1353 for (scnwidth = WIDTH; --scnwidth;) { 1354 key <<= 1; 1355 *p++ = key & 0200 ? c : BACKGND; 1356 } 1357 return (p); 1358} 1359 1360#define TRC(q) (((q)-' ')&0177) 1361 1362static void 1363scan_out(struct printer *pp, int scfd, char *scsp, int dlm) 1364{ 1365 register char *strp; 1366 register int nchrs, j; 1367 char outbuf[LINELEN+1], *sp, c, cc; 1368 int d, scnhgt; 1369 1370 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1371 strp = &outbuf[0]; 1372 sp = scsp; 1373 for (nchrs = 0; ; ) { 1374 d = dropit(c = TRC(cc = *sp++)); 1375 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1376 for (j = WIDTH; --j;) 1377 *strp++ = BACKGND; 1378 else 1379 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1380 if (*sp == dlm || *sp == '\0' || 1381 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1382 break; 1383 *strp++ = BACKGND; 1384 *strp++ = BACKGND; 1385 } 1386 while (*--strp == BACKGND && strp >= outbuf) 1387 ; 1388 strp++; 1389 *strp++ = '\n'; 1390 (void) write(scfd, outbuf, strp-outbuf); 1391 } 1392} 1393 1394static int 1395dropit(int c) 1396{ 1397 switch(c) { 1398 1399 case TRC('_'): 1400 case TRC(';'): 1401 case TRC(','): 1402 case TRC('g'): 1403 case TRC('j'): 1404 case TRC('p'): 1405 case TRC('q'): 1406 case TRC('y'): 1407 return (DROP); 1408 1409 default: 1410 return (0); 1411 } 1412} 1413 1414/* 1415 * sendmail --- 1416 * tell people about job completion 1417 */ 1418static void 1419sendmail(struct printer *pp, char *userid, int bombed) 1420{ 1421 register int i; 1422 int p[2], s; 1423 register const char *cp; 1424 struct stat stb; 1425 FILE *fp; 1426 1427 pipe(p); 1428 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1429 dup2(p[0], 0); 1430 closelog(); 1431 closeallfds(3); 1432 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1433 cp++; 1434 else 1435 cp = _PATH_SENDMAIL; 1436 execl(_PATH_SENDMAIL, cp, "-t", (char *)0); 1437 _exit(0); 1438 } else if (s > 0) { /* parent */ 1439 dup2(p[1], 1); 1440 printf("To: %s@%s\n", userid, origin_host); 1441 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1442 *jobname ? jobname : "<unknown>"); 1443 printf("Reply-To: root@%s\n\n", local_host); 1444 printf("Your printer job "); 1445 if (*jobname) 1446 printf("(%s) ", jobname); 1447 1448 switch (bombed) { 1449 case OK: 1450 cp = "OK"; 1451 printf("\ncompleted successfully\n"); 1452 break; 1453 default: 1454 case FATALERR: 1455 cp = "FATALERR"; 1456 printf("\ncould not be printed\n"); 1457 break; 1458 case NOACCT: 1459 cp = "NOACCT"; 1460 printf("\ncould not be printed without an account on %s\n", 1461 local_host); 1462 break; 1463 case FILTERERR: 1464 cp = "FILTERERR"; 1465 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1466 || (fp = fopen(tempstderr, "r")) == NULL) { 1467 printf("\nhad some errors and may not have printed\n"); 1468 break; 1469 } 1470 printf("\nhad the following errors and may not have printed:\n"); 1471 while ((i = getc(fp)) != EOF) 1472 putchar(i); 1473 (void) fclose(fp); 1474 break; 1475 case ACCESS: 1476 cp = "ACCESS"; 1477 printf("\nwas not printed because it was not linked to the original file\n"); 1478 } 1479 fflush(stdout); 1480 (void) close(1); 1481 } else { 1482 syslog(LOG_WARNING, "unable to send mail to %s: %m", userid); 1483 return; 1484 } 1485 (void) close(p[0]); 1486 (void) close(p[1]); 1487 wait(NULL); 1488 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1489 userid, *jobname ? jobname : "<unknown>", pp->printer, cp); 1490} 1491 1492/* 1493 * dofork - fork with retries on failure 1494 */ 1495static int 1496dofork(const struct printer *pp, int action) 1497{ 1498 int i, fail, forkpid; 1499 struct passwd *pwd; 1500 1501 forkpid = -1; 1502 if (daemon_uname == NULL) { 1503 pwd = getpwuid(pp->daemon_user); 1504 if (pwd == NULL) { 1505 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file", 1506 pp->printer, pp->daemon_user); 1507 goto error_ret; 1508 } 1509 daemon_uname = strdup(pwd->pw_name); 1510 daemon_defgid = pwd->pw_gid; 1511 } 1512 1513 for (i = 0; i < 20; i++) { 1514 forkpid = fork(); 1515 if (forkpid < 0) { 1516 sleep((unsigned)(i*i)); 1517 continue; 1518 } 1519 /* 1520 * Child should run as daemon instead of root 1521 */ 1522 if (forkpid == 0) { 1523 errno = 0; 1524 fail = initgroups(daemon_uname, daemon_defgid); 1525 if (fail) { 1526 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m", 1527 pp->printer, daemon_uname, daemon_defgid); 1528 break; 1529 } 1530 fail = setgid(daemon_defgid); 1531 if (fail) { 1532 syslog(LOG_ERR, "%s: setgid(%u): %m", 1533 pp->printer, daemon_defgid); 1534 break; 1535 } 1536 fail = setuid(pp->daemon_user); 1537 if (fail) { 1538 syslog(LOG_ERR, "%s: setuid(%ld): %m", 1539 pp->printer, pp->daemon_user); 1540 break; 1541 } 1542 } 1543 return forkpid; 1544 } 1545 1546 /* 1547 * An error occurred. If the error is in the child process, then 1548 * this routine MUST always exit(). DORETURN only effects how 1549 * errors should be handled in the parent process. 1550 */ 1551error_ret: 1552 if (forkpid == 0) { 1553 syslog(LOG_ERR, "%s: dofork(): aborting child process...", 1554 pp->printer); 1555 exit(1); 1556 } 1557 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer); 1558 1559 sleep(1); /* throttle errors, as a safety measure */ 1560 switch (action) { 1561 case DORETURN: 1562 return -1; 1563 default: 1564 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1565 /* FALLTHROUGH */ 1566 case DOABORT: 1567 exit(1); 1568 } 1569 /*NOTREACHED*/ 1570} 1571 1572/* 1573 * Kill child processes to abort current job. 1574 */ 1575static void 1576abortpr(int signo __unused) 1577{ 1578 1579 (void) unlink(tempstderr); 1580 kill(0, SIGINT); 1581 if (ofilter > 0) 1582 kill(ofilter, SIGCONT); 1583 while (wait(NULL) > 0) 1584 ; 1585 if (ofilter > 0 && tfd != -1) 1586 unlink(tfile); 1587 exit(0); 1588} 1589 1590static void 1591init(struct printer *pp) 1592{ 1593 char *s; 1594 1595 sprintf(&width[2], "%ld", pp->page_width); 1596 sprintf(&length[2], "%ld", pp->page_length); 1597 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1598 sprintf(&pxlength[2], "%ld", pp->page_plength); 1599 if ((s = checkremote(pp)) != 0) { 1600 syslog(LOG_WARNING, "%s", s); 1601 free(s); 1602 } 1603} 1604 1605void 1606startprinting(const char *printer) 1607{ 1608 struct printer myprinter, *pp = &myprinter; 1609 int status; 1610 1611 init_printer(pp); 1612 status = getprintcap(printer, pp); 1613 switch(status) { 1614 case PCAPERR_OSERR: 1615 syslog(LOG_ERR, "can't open printer description file: %m"); 1616 exit(1); 1617 case PCAPERR_NOTFOUND: 1618 syslog(LOG_ERR, "unknown printer: %s", printer); 1619 exit(1); 1620 case PCAPERR_TCLOOP: 1621 fatal(pp, "potential reference loop detected in printcap file"); 1622 default: 1623 break; 1624 } 1625 printjob(pp); 1626} 1627 1628/* 1629 * Acquire line printer or remote connection. 1630 */ 1631static void 1632openpr(const struct printer *pp) 1633{ 1634 int p[2]; 1635 char *cp; 1636 1637 if (pp->remote) { 1638 openrem(pp); 1639 /* 1640 * Lpd does support the setting of 'of=' filters for 1641 * jobs going to remote machines, but that does not 1642 * have the same meaning as 'of=' does when handling 1643 * local print queues. For remote machines, all 'of=' 1644 * filter processing is handled in sendfile(), and that 1645 * does not use these global "output filter" variables. 1646 */ 1647 ofd = -1; 1648 ofilter = 0; 1649 return; 1650 } else if (*pp->lp) { 1651 if ((cp = strchr(pp->lp, '@')) != NULL) 1652 opennet(pp); 1653 else 1654 opentty(pp); 1655 } else { 1656 syslog(LOG_ERR, "%s: no line printer device or host name", 1657 pp->printer); 1658 exit(1); 1659 } 1660 1661 /* 1662 * Start up an output filter, if needed. 1663 */ 1664 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1665 pipe(p); 1666 if (pp->remote) { 1667 strcpy(tfile, TFILENAME); 1668 tfd = mkstemp(tfile); 1669 } 1670 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1671 dup2(p[0], 0); /* pipe is std in */ 1672 /* tfile/printer is stdout */ 1673 dup2(pp->remote ? tfd : pfd, 1); 1674 closelog(); 1675 closeallfds(3); 1676 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1677 cp = pp->filters[LPF_OUTPUT]; 1678 else 1679 cp++; 1680 execl(pp->filters[LPF_OUTPUT], cp, width, length, 1681 (char *)0); 1682 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1683 pp->filters[LPF_OUTPUT]); 1684 exit(1); 1685 } 1686 (void) close(p[0]); /* close input side */ 1687 ofd = p[1]; /* use pipe for output */ 1688 } else { 1689 ofd = pfd; 1690 ofilter = 0; 1691 } 1692} 1693 1694/* 1695 * Printer connected directly to the network 1696 * or to a terminal server on the net 1697 */ 1698static void 1699opennet(const struct printer *pp) 1700{ 1701 register int i; 1702 int resp; 1703 u_long port; 1704 char *ep; 1705 void (*savealrm)(int); 1706 1707 port = strtoul(pp->lp, &ep, 0); 1708 if (*ep != '@' || port > 65535) { 1709 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1710 pp->lp); 1711 exit(1); 1712 } 1713 ep++; 1714 1715 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1716 resp = -1; 1717 savealrm = signal(SIGALRM, alarmhandler); 1718 alarm(pp->conn_timeout); 1719 pfd = getport(pp, ep, port); 1720 alarm(0); 1721 (void)signal(SIGALRM, savealrm); 1722 if (pfd < 0 && errno == ECONNREFUSED) 1723 resp = 1; 1724 else if (pfd >= 0) { 1725 /* 1726 * need to delay a bit for rs232 lines 1727 * to stabilize in case printer is 1728 * connected via a terminal server 1729 */ 1730 delay(500); 1731 break; 1732 } 1733 if (i == 1) { 1734 if (resp < 0) 1735 pstatus(pp, "waiting for %s to come up", 1736 pp->lp); 1737 else 1738 pstatus(pp, 1739 "waiting for access to printer on %s", 1740 pp->lp); 1741 } 1742 sleep(i); 1743 } 1744 pstatus(pp, "sending to %s port %lu", ep, port); 1745} 1746 1747/* 1748 * Printer is connected to an RS232 port on this host 1749 */ 1750static void 1751opentty(const struct printer *pp) 1752{ 1753 register int i; 1754 1755 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1756 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1757 if (pfd >= 0) { 1758 delay(500); 1759 break; 1760 } 1761 if (errno == ENOENT) { 1762 syslog(LOG_ERR, "%s: %m", pp->lp); 1763 exit(1); 1764 } 1765 if (i == 1) 1766 pstatus(pp, 1767 "waiting for %s to become ready (offline?)", 1768 pp->printer); 1769 sleep(i); 1770 } 1771 if (isatty(pfd)) 1772 setty(pp); 1773 pstatus(pp, "%s is ready and printing", pp->printer); 1774} 1775 1776/* 1777 * Printer is on a remote host 1778 */ 1779static void 1780openrem(const struct printer *pp) 1781{ 1782 register int i; 1783 int resp; 1784 void (*savealrm)(int); 1785 1786 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1787 resp = -1; 1788 savealrm = signal(SIGALRM, alarmhandler); 1789 alarm(pp->conn_timeout); 1790 pfd = getport(pp, pp->remote_host, 0); 1791 alarm(0); 1792 (void)signal(SIGALRM, savealrm); 1793 if (pfd >= 0) { 1794 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1795 (char *)0) 1796 == 2 + strlen(pp->remote_queue)) 1797 && (resp = response(pp)) == 0) 1798 break; 1799 (void) close(pfd); 1800 } 1801 if (i == 1) { 1802 if (resp < 0) 1803 pstatus(pp, "waiting for %s to come up", 1804 pp->remote_host); 1805 else { 1806 pstatus(pp, 1807 "waiting for queue to be enabled on %s", 1808 pp->remote_host); 1809 i = 256; 1810 } 1811 } 1812 sleep(i); 1813 } 1814 pstatus(pp, "sending to %s", pp->remote_host); 1815} 1816 1817/* 1818 * setup tty lines. 1819 */ 1820static void 1821setty(const struct printer *pp) 1822{ 1823 struct termios ttybuf; 1824 1825 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1826 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1827 exit(1); 1828 } 1829 if (tcgetattr(pfd, &ttybuf) < 0) { 1830 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1831 exit(1); 1832 } 1833 if (pp->baud_rate > 0) 1834 cfsetspeed(&ttybuf, pp->baud_rate); 1835 if (pp->mode_set) { 1836 char *s = strdup(pp->mode_set), *tmp; 1837 1838 while ((tmp = strsep(&s, ",")) != NULL) { 1839 (void) msearch(tmp, &ttybuf); 1840 } 1841 } 1842 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1843 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1844 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1845 } 1846 } 1847} 1848 1849#ifdef __STDC__ 1850#include <stdarg.h> 1851#else 1852#include <varargs.h> 1853#endif 1854 1855static void 1856#ifdef __STDC__ 1857pstatus(const struct printer *pp, const char *msg, ...) 1858#else 1859pstatus(pp, msg, va_alist) 1860 const struct printer *pp; 1861 char *msg; 1862 va_dcl 1863#endif 1864{ 1865 int fd; 1866 char *buf; 1867 va_list ap; 1868#ifdef __STDC__ 1869 va_start(ap, msg); 1870#else 1871 va_start(ap); 1872#endif 1873 1874 umask(0); 1875 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1876 if (fd < 0) { 1877 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1878 exit(1); 1879 } 1880 ftruncate(fd, 0); 1881 vasprintf(&buf, msg, ap); 1882 va_end(ap); 1883 writel(fd, buf, "\n", (char *)0); 1884 close(fd); 1885 free(buf); 1886} 1887 1888void 1889alarmhandler(int signo __unused) 1890{ 1891 /* the signal is ignored */ 1892 /* (the '__unused' is just to avoid a compile-time warning) */ 1893} 1894