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