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