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