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