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