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