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