119static void banner __P((char *, char *)); 120static int dofork __P((int)); 121static int dropit __P((int)); 122static void init __P((void)); 123static void openpr __P((void)); 124static void opennet __P((char *)); 125static void opentty __P((void)); 126static void openrem __P((void)); 127static int print __P((int, char *)); 128static int printit __P((char *)); 129static void pstatus __P((const char *, ...)); 130static char response __P((void)); 131static void scan_out __P((int, char *, int)); 132static char *scnline __P((int, char *, int)); 133static int sendfile __P((int, char *, char)); 134static int sendit __P((char *)); 135static void sendmail __P((char *, int)); 136static void setty __P((void)); 137 138void 139printjob() 140{ 141 struct stat stb; 142 register struct queue *q, **qp; 143 struct queue **queue; 144 register int i, nitems; 145 off_t pidoff; 146 int errcnt, count = 0; 147 148 init(); /* set up capabilities */ 149 (void) write(1, "", 1); /* ack that daemon is started */ 150 (void) close(2); /* set up log file */ 151 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 152 syslog(LOG_ERR, "%s: %m", LF); 153 (void) open(_PATH_DEVNULL, O_WRONLY); 154 } 155 setgid(getegid()); 156 pid = getpid(); /* for use with lprm */ 157 setpgrp(0, pid); 158 signal(SIGHUP, abortpr); 159 signal(SIGINT, abortpr); 160 signal(SIGQUIT, abortpr); 161 signal(SIGTERM, abortpr); 162 163 (void) mktemp(tempfile); 164 165 /* 166 * uses short form file names 167 */ 168 if (chdir(SD) < 0) { 169 syslog(LOG_ERR, "%s: %m", SD); 170 exit(1); 171 } 172 if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 173 exit(0); /* printing disabled */ 174 lfd = open(LO, O_WRONLY|O_CREAT, 0644); 175 if (lfd < 0) { 176 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 177 exit(1); 178 } 179 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 180 if (errno == EWOULDBLOCK) /* active deamon present */ 181 exit(0); 182 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 183 exit(1); 184 } 185 ftruncate(lfd, 0); 186 /* 187 * write process id for others to know 188 */ 189 sprintf(line, "%u\n", pid); 190 pidoff = i = strlen(line); 191 if (write(lfd, line, i) != i) { 192 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 193 exit(1); 194 } 195 /* 196 * search the spool directory for work and sort by queue order. 197 */ 198 if ((nitems = getq(&queue)) < 0) { 199 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 200 exit(1); 201 } 202 if (nitems == 0) /* no work to do */ 203 exit(0); 204 if (stb.st_mode & 01) { /* reset queue flag */ 205 if (fchmod(lfd, stb.st_mode & 0776) < 0) 206 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 207 } 208 openpr(); /* open printer or remote */ 209again: 210 /* 211 * we found something to do now do it -- 212 * write the name of the current control file into the lock file 213 * so the spool queue program can tell what we're working on 214 */ 215 for (qp = queue; nitems--; free((char *) q)) { 216 q = *qp++; 217 if (stat(q->q_name, &stb) < 0) 218 continue; 219 errcnt = 0; 220 restart: 221 (void) lseek(lfd, pidoff, 0); 222 (void) snprintf(line, sizeof(line), "%s\n", q->q_name); 223 i = strlen(line); 224 if (write(lfd, line, i) != i) 225 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 226 if (!remote) 227 i = printit(q->q_name); 228 else 229 i = sendit(q->q_name); 230 /* 231 * Check to see if we are supposed to stop printing or 232 * if we are to rebuild the queue. 233 */ 234 if (fstat(lfd, &stb) == 0) { 235 /* stop printing before starting next job? */ 236 if (stb.st_mode & 0100) 237 goto done; 238 /* rebuild queue (after lpc topq) */ 239 if (stb.st_mode & 01) { 240 for (free((char *) q); nitems--; free((char *) q)) 241 q = *qp++; 242 if (fchmod(lfd, stb.st_mode & 0776) < 0) 243 syslog(LOG_WARNING, "%s: %s: %m", 244 printer, LO); 245 break; 246 } 247 } 248 if (i == OK) /* file ok and printed */ 249 count++; 250 else if (i == REPRINT && ++errcnt < 5) { 251 /* try reprinting the job */ 252 syslog(LOG_INFO, "restarting %s", printer); 253 if (ofilter > 0) { 254 kill(ofilter, SIGCONT); /* to be sure */ 255 (void) close(ofd); 256 while ((i = wait(NULL)) > 0 && i != ofilter) 257 ; 258 ofilter = 0; 259 } 260 (void) close(pfd); /* close printer */ 261 if (ftruncate(lfd, pidoff) < 0) 262 syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 263 openpr(); /* try to reopen printer */ 264 goto restart; 265 } else { 266 syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 267 remote ? "sent to remote host" : "printed", q->q_name); 268 if (i == REPRINT) { 269 /* ensure we don't attempt this job again */ 270 (void) unlink(q->q_name); 271 q->q_name[0] = 'd'; 272 (void) unlink(q->q_name); 273 if (logname[0]) 274 sendmail(logname, FATALERR); 275 } 276 } 277 } 278 free((char *) queue); 279 /* 280 * search the spool directory for more work. 281 */ 282 if ((nitems = getq(&queue)) < 0) { 283 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 284 exit(1); 285 } 286 if (nitems == 0) { /* no more work to do */ 287 done: 288 if (count > 0) { /* Files actually printed */ 289 if (!SF && !tof) 290 (void) write(ofd, FF, strlen(FF)); 291 if (TR != NULL) /* output trailer */ 292 (void) write(ofd, TR, strlen(TR)); 293 } 294 (void) close(ofd); 295 (void) wait(NULL); 296 (void) unlink(tempfile); 297 exit(0); 298 } 299 goto again; 300} 301 302char fonts[4][50]; /* fonts for troff */ 303 304char ifonts[4][40] = { 305 _PATH_VFONTR, 306 _PATH_VFONTI, 307 _PATH_VFONTB, 308 _PATH_VFONTS, 309}; 310 311/* 312 * The remaining part is the reading of the control file (cf) 313 * and performing the various actions. 314 */ 315static int 316printit(file) 317 char *file; 318{ 319 register int i; 320 char *cp; 321 int bombed = OK; 322 323 /* 324 * open control file; ignore if no longer there. 325 */ 326 if ((cfp = fopen(file, "r")) == NULL) { 327 syslog(LOG_INFO, "%s: %s: %m", printer, file); 328 return(OK); 329 } 330 /* 331 * Reset troff fonts. 332 */ 333 for (i = 0; i < 4; i++) 334 strcpy(fonts[i], ifonts[i]); 335 sprintf(&width[2], "%ld", PW); 336 strcpy(indent+2, "0"); 337 338 /* 339 * read the control file for work to do 340 * 341 * file format -- first character in the line is a command 342 * rest of the line is the argument. 343 * valid commands are: 344 * 345 * S -- "stat info" for symbolic link protection 346 * J -- "job name" on banner page 347 * C -- "class name" on banner page 348 * L -- "literal" user's name to print on banner 349 * T -- "title" for pr 350 * H -- "host name" of machine where lpr was done 351 * P -- "person" user's login name 352 * I -- "indent" amount to indent output 353 * R -- laser dpi "resolution" 354 * f -- "file name" name of text file to print 355 * l -- "file name" text file with control chars 356 * p -- "file name" text file to print with pr(1) 357 * t -- "file name" troff(1) file to print 358 * n -- "file name" ditroff(1) file to print 359 * d -- "file name" dvi file to print 360 * g -- "file name" plot(1G) file to print 361 * v -- "file name" plain raster file to print 362 * c -- "file name" cifplot file to print 363 * 1 -- "R font file" for troff 364 * 2 -- "I font file" for troff 365 * 3 -- "B font file" for troff 366 * 4 -- "S font file" for troff 367 * N -- "name" of file (used by lpq) 368 * U -- "unlink" name of file to remove 369 * (after we print it. (Pass 2 only)). 370 * M -- "mail" to user when done printing 371 * 372 * getline reads a line and expands tabs to blanks 373 */ 374 375 /* pass 1 */ 376 377 while (getline(cfp)) 378 switch (line[0]) { 379 case 'H': 380 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 381 fromhost[sizeof(fromhost) - 1] = '\0'; 382 if (class[0] == '\0') { 383 strncpy(class, line+1, sizeof(class) - 1); 384 class[sizeof(class) - 1] = '\0'; 385 } 386 continue; 387 388 case 'P': 389 strncpy(logname, line+1, sizeof(logname) - 1); 390 logname[sizeof(logname) - 1] = '\0'; 391 if (RS) { /* restricted */ 392 if (getpwnam(logname) == NULL) { 393 bombed = NOACCT; 394 sendmail(line+1, bombed); 395 goto pass2; 396 } 397 } 398 continue; 399 400 case 'S': 401 cp = line+1; 402 i = 0; 403 while (*cp >= '0' && *cp <= '9') 404 i = i * 10 + (*cp++ - '0'); 405 fdev = i; 406 cp++; 407 i = 0; 408 while (*cp >= '0' && *cp <= '9') 409 i = i * 10 + (*cp++ - '0'); 410 fino = i; 411 continue; 412 413 case 'J': 414 if (line[1] != '\0') { 415 strncpy(jobname, line+1, sizeof(jobname) - 1); 416 jobname[sizeof(jobname) - 1] = '\0'; 417 } else 418 strcpy(jobname, " "); 419 continue; 420 421 case 'C': 422 if (line[1] != '\0') 423 strncpy(class, line+1, sizeof(class) - 1); 424 else if (class[0] == '\0') 425 gethostname(class, sizeof(class)); 426 class[sizeof(class) - 1] = '\0'; 427 continue; 428 429 case 'T': /* header title for pr */ 430 strncpy(title, line+1, sizeof(title) - 1); 431 title[sizeof(title) - 1] = '\0'; 432 continue; 433 434 case 'L': /* identification line */ 435 if (!SH && !HL) 436 banner(line+1, jobname); 437 continue; 438 439 case '1': /* troff fonts */ 440 case '2': 441 case '3': 442 case '4': 443 if (line[1] != '\0') { 444 strncpy(fonts[line[0]-'1'], line+1, 445 50-1); 446 fonts[line[0]-'1'][50-1] = '\0'; 447 } 448 continue; 449 450 case 'W': /* page width */ 451 strncpy(width+2, line+1, sizeof(width) - 3); 452 width[2+sizeof(width) - 3] = '\0'; 453 continue; 454 455 case 'I': /* indent amount */ 456 strncpy(indent+2, line+1, sizeof(indent) - 3); 457 indent[2+sizeof(indent) - 3] = '\0'; 458 continue; 459 460 default: /* some file to print */ 461 switch (i = print(line[0], line+1)) { 462 case ERROR: 463 if (bombed == OK) 464 bombed = FATALERR; 465 break; 466 case REPRINT: 467 (void) fclose(cfp); 468 return(REPRINT); 469 case FILTERERR: 470 case ACCESS: 471 bombed = i; 472 sendmail(logname, bombed); 473 } 474 title[0] = '\0'; 475 continue; 476 477 case 'N': 478 case 'U': 479 case 'M': 480 case 'R': 481 continue; 482 } 483 484 /* pass 2 */ 485 486pass2: 487 fseek(cfp, 0L, 0); 488 while (getline(cfp)) 489 switch (line[0]) { 490 case 'L': /* identification line */ 491 if (!SH && HL) 492 banner(line+1, jobname); 493 continue; 494 495 case 'M': 496 if (bombed < NOACCT) /* already sent if >= NOACCT */ 497 sendmail(line+1, bombed); 498 continue; 499 500 case 'U': 501 if (strchr(line+1, '/')) 502 continue; 503 (void) unlink(line+1); 504 } 505 /* 506 * clean-up in case another control file exists 507 */ 508 (void) fclose(cfp); 509 (void) unlink(file); 510 return(bombed == OK ? OK : ERROR); 511} 512 513/* 514 * Print a file. 515 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 516 * Return -1 if a non-recoverable error occured, 517 * 2 if the filter detected some errors (but printed the job anyway), 518 * 1 if we should try to reprint this job and 519 * 0 if all is well. 520 * Note: all filters take stdin as the file, stdout as the printer, 521 * stderr as the log file, and must not ignore SIGINT. 522 */ 523static int 524print(format, file) 525 int format; 526 char *file; 527{ 528 register int n; 529 register char *prog; 530 int dtablesize, fi, fo; 531 FILE *fp; 532 char *av[15], buf[BUFSIZ]; 533 int pid, p[2], stopped = 0; 534 union wait status; 535 struct stat stb; 536 537 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 538 return(ERROR); 539 /* 540 * Check to see if data file is a symbolic link. If so, it should 541 * still point to the same file or someone is trying to print 542 * something he shouldn't. 543 */ 544 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 545 (stb.st_dev != fdev || stb.st_ino != fino)) 546 return(ACCESS); 547 if (!SF && !tof) { /* start on a fresh page */ 548 (void) write(ofd, FF, strlen(FF)); 549 tof = 1; 550 } 551 if (IF == NULL && (format == 'f' || format == 'l')) { 552 tof = 0; 553 while ((n = read(fi, buf, BUFSIZ)) > 0) 554 if (write(ofd, buf, n) != n) { 555 (void) close(fi); 556 return(REPRINT); 557 } 558 (void) close(fi); 559 return(OK); 560 } 561 switch (format) { 562 case 'p': /* print file using 'pr' */ 563 if (IF == NULL) { /* use output filter */ 564 prog = _PATH_PR; 565 av[0] = "pr"; 566 av[1] = width; 567 av[2] = length; 568 av[3] = "-h"; 569 av[4] = *title ? title : " "; 570 av[5] = "-F"; 571 av[6] = 0; 572 fo = ofd; 573 goto start; 574 } 575 pipe(p); 576 if ((prchild = dofork(DORETURN)) == 0) { /* child */ 577 dup2(fi, 0); /* file is stdin */ 578 dup2(p[1], 1); /* pipe is stdout */ 579 closelog(); 580 for (n = 3, dtablesize = getdtablesize(); 581 n < dtablesize; n++) 582 (void) close(n); 583 execl(_PATH_PR, "pr", width, length, 584 "-h", *title ? title : " ", "-F", 0); 585 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 586 exit(2); 587 } 588 (void) close(p[1]); /* close output side */ 589 (void) close(fi); 590 if (prchild < 0) { 591 prchild = 0; 592 (void) close(p[0]); 593 return(ERROR); 594 } 595 fi = p[0]; /* use pipe for input */ 596 case 'f': /* print plain text file */ 597 prog = IF; 598 av[1] = width; 599 av[2] = length; 600 av[3] = indent; 601 n = 4; 602 break; 603 case 'l': /* like 'f' but pass control characters */ 604 prog = IF; 605 av[1] = "-c"; 606 av[2] = width; 607 av[3] = length; 608 av[4] = indent; 609 n = 5; 610 break; 611 case 'r': /* print a fortran text file */ 612 prog = RF; 613 av[1] = width; 614 av[2] = length; 615 n = 3; 616 break; 617 case 't': /* print troff output */ 618 case 'n': /* print ditroff output */ 619 case 'd': /* print tex output */ 620 (void) unlink(".railmag"); 621 if ((fo = creat(".railmag", FILMOD)) < 0) { 622 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 623 (void) unlink(".railmag"); 624 } else { 625 for (n = 0; n < 4; n++) { 626 if (fonts[n][0] != '/') 627 (void) write(fo, _PATH_VFONT, 628 sizeof(_PATH_VFONT) - 1); 629 (void) write(fo, fonts[n], strlen(fonts[n])); 630 (void) write(fo, "\n", 1); 631 } 632 (void) close(fo); 633 } 634 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 635 av[1] = pxwidth; 636 av[2] = pxlength; 637 n = 3; 638 break; 639 case 'c': /* print cifplot output */ 640 prog = CF; 641 av[1] = pxwidth; 642 av[2] = pxlength; 643 n = 3; 644 break; 645 case 'g': /* print plot(1G) output */ 646 prog = GF; 647 av[1] = pxwidth; 648 av[2] = pxlength; 649 n = 3; 650 break; 651 case 'v': /* print raster output */ 652 prog = VF; 653 av[1] = pxwidth; 654 av[2] = pxlength; 655 n = 3; 656 break; 657 default: 658 (void) close(fi); 659 syslog(LOG_ERR, "%s: illegal format character '%c'", 660 printer, format); 661 return(ERROR); 662 } 663 if (prog == NULL) { 664 (void) close(fi); 665 syslog(LOG_ERR, 666 "%s: no filter found in printcap for format character '%c'", 667 printer, format); 668 return(ERROR); 669 } 670 if ((av[0] = strrchr(prog, '/')) != NULL) 671 av[0]++; 672 else 673 av[0] = prog; 674 av[n++] = "-n"; 675 av[n++] = logname; 676 av[n++] = "-h"; 677 av[n++] = fromhost; 678 av[n++] = AF; 679 av[n] = 0; 680 fo = pfd; 681 if (ofilter > 0) { /* stop output filter */ 682 write(ofd, "\031\1", 2); 683 while ((pid = 684 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 685 ; 686 if (status.w_stopval != WSTOPPED) { 687 (void) close(fi); 688 syslog(LOG_WARNING, 689 "%s: output filter died (retcode=%d termsig=%d)", 690 printer, status.w_retcode, status.w_termsig); 691 return(REPRINT); 692 } 693 stopped++; 694 } 695start: 696 if ((child = dofork(DORETURN)) == 0) { /* child */ 697 dup2(fi, 0); 698 dup2(fo, 1); 699 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 700 if (n >= 0) 701 dup2(n, 2); 702 closelog(); 703 for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++) 704 (void) close(n); 705 execv(prog, av); 706 syslog(LOG_ERR, "cannot execv %s", prog); 707 exit(2); 708 } 709 (void) close(fi); 710 if (child < 0) 711 status.w_retcode = 100; 712 else 713 while ((pid = wait((int *)&status)) > 0 && pid != child) 714 ; 715 child = 0; 716 prchild = 0; 717 if (stopped) { /* restart output filter */ 718 if (kill(ofilter, SIGCONT) < 0) { 719 syslog(LOG_ERR, "cannot restart output filter"); 720 exit(1); 721 } 722 } 723 tof = 0; 724 725 /* Copy filter output to "lf" logfile */ 726 if ((fp = fopen(tempfile, "r"))) { 727 while (fgets(buf, sizeof(buf), fp)) 728 fputs(buf, stderr); 729 fclose(fp); 730 } 731 732 if (!WIFEXITED(status)) { 733 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 734 printer, format, status.w_termsig); 735 return(ERROR); 736 } 737 switch (status.w_retcode) { 738 case 0: 739 tof = 1; 740 return(OK); 741 case 1: 742 return(REPRINT); 743 case 2: 744 return(ERROR); 745 default: 746 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 747 printer, format, status.w_retcode); 748 return(FILTERERR); 749 } 750} 751 752/* 753 * Send the daemon control file (cf) and any data files. 754 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 755 * 0 if all is well. 756 */ 757static int 758sendit(file) 759 char *file; 760{ 761 register int i, err = OK; 762 char *cp, last[BUFSIZ]; 763 764 /* 765 * open control file 766 */ 767 if ((cfp = fopen(file, "r")) == NULL) 768 return(OK); 769 /* 770 * read the control file for work to do 771 * 772 * file format -- first character in the line is a command 773 * rest of the line is the argument. 774 * commands of interest are: 775 * 776 * a-z -- "file name" name of file to print 777 * U -- "unlink" name of file to remove 778 * (after we print it. (Pass 2 only)). 779 */ 780 781 /* 782 * pass 1 783 */ 784 while (getline(cfp)) { 785 again: 786 if (line[0] == 'S') { 787 cp = line+1; 788 i = 0; 789 while (*cp >= '0' && *cp <= '9') 790 i = i * 10 + (*cp++ - '0'); 791 fdev = i; 792 cp++; 793 i = 0; 794 while (*cp >= '0' && *cp <= '9') 795 i = i * 10 + (*cp++ - '0'); 796 fino = i; 797 } else if (line[0] == 'H') { 798 strcpy(fromhost, line+1); 799 if (class[0] == '\0') 800 strncpy(class, line+1, sizeof(class) - 1); 801 } else if (line[0] == 'P') { 802 strncpy(logname, line+1, sizeof(logname) - 1); 803 if (RS) { /* restricted */ 804 if (getpwnam(logname) == NULL) { 805 sendmail(line+1, NOACCT); 806 err = ERROR; 807 break; 808 } 809 } 810 } else if (line[0] == 'I') { 811 strncpy(indent+2, line+1, sizeof(indent) - 3); 812 } else if (line[0] >= 'a' && line[0] <= 'z') { 813 strcpy(last, line); 814 while (i = getline(cfp)) 815 if (strcmp(last, line)) 816 break; 817 switch (sendfile('\3', last+1, *last)) { 818 case OK: 819 if (i) 820 goto again; 821 break; 822 case REPRINT: 823 (void) fclose(cfp); 824 return(REPRINT); 825 case ACCESS: 826 sendmail(logname, ACCESS); 827 case ERROR: 828 err = ERROR; 829 } 830 break; 831 } 832 } 833 if (err == OK && sendfile('\2', file, '\0') > 0) { 834 (void) fclose(cfp); 835 return(REPRINT); 836 } 837 /* 838 * pass 2 839 */ 840 fseek(cfp, 0L, 0); 841 while (getline(cfp)) 842 if (line[0] == 'U' && !strchr(line+1, '/')) 843 (void) unlink(line+1); 844 /* 845 * clean-up in case another control file exists 846 */ 847 (void) fclose(cfp); 848 (void) unlink(file); 849 return(err); 850} 851 852/* 853 * Send a data file to the remote machine and spool it. 854 * Return positive if we should try resending. 855 */ 856static int 857sendfile(type, file, format) 858 int type; 859 char *file; 860 char format; 861{ 862 register int f, i, amt; 863 struct stat stb; 864 char buf[BUFSIZ]; 865 int sizerr, resp, closedpr; 866 867 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 868 return(ERROR); 869 /* 870 * Check to see if data file is a symbolic link. If so, it should 871 * still point to the same file or someone is trying to print something 872 * he shouldn't. 873 */ 874 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 875 (stb.st_dev != fdev || stb.st_ino != fino)) 876 return(ACCESS); 877 878 sizerr = 0; 879 closedpr = 0; 880 if (type == '\3') { 881 if (IF) { 882 /* 883 * We're sending something with an ifilter, we have to 884 * run the ifilter and store the output as a 885 * temporary file (tfile)... the protocol requires us 886 * to send the file size 887 */ 888 char *av[15]; 889 int n; 890 int nfd; 891 int ifilter; 892 union wait status; 893 894 strcpy(tfile,TFILENAME); 895 if ((tfd = mkstemp(tfile)) == -1) { 896 syslog(LOG_ERR, "mkstemp: %m"); 897 return(ERROR); 898 } 899 if ((av[0] = strrchr(IF, '/')) == NULL) 900 av[0] = IF; 901 else 902 av[0]++; 903 if (format == 'l') 904 av[n=1] = "-c"; 905 else 906 n = 0; 907 av[++n] = width; 908 av[++n] = length; 909 av[++n] = indent; 910 av[++n] = "-n"; 911 av[++n] = logname; 912 av[++n] = "-h"; 913 av[++n] = fromhost; 914 av[++n] = AF; 915 av[++n] = 0; 916 if ((ifilter = dofork(DORETURN)) == 0) { /* child */ 917 dup2(f, 0); 918 dup2(tfd, 1); 919 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 920 if (n >= 0) 921 dup2(n, 2); 922 closelog(); 923 for (n = 3, nfd = getdtablesize(); n < nfd; n++) 924 (void) close(n); 925 execv(IF, av); 926 syslog(LOG_ERR, "cannot execv %s", IF); 927 exit(2); 928 } 929 (void) close(f); 930 if (ifilter < 0) 931 status.w_retcode = 100; 932 else 933 while ((pid = wait((int *)&status)) > 0 && 934 pid != ifilter) 935 ; 936 switch (status.w_retcode) { 937 case 0: 938 break; 939 case 1: 940 unlink(tfile); 941 return(REPRINT); 942 case 2: 943 unlink(tfile); 944 return(ERROR); 945 default: 946 syslog(LOG_WARNING, "%s: filter '%c' exited" 947 " (retcode=%d)", 948 printer, format, status.w_retcode); 949 unlink(tfile); 950 return(FILTERERR); 951 } 952 if (fstat(tfd, &stb) < 0) /* the size of tfile */ 953 return(ERROR); 954 f = tfd; 955 lseek(f,0,SEEK_SET); 956 } else if (ofilter) { 957 /* 958 * We're sending something with an ofilter, we have to 959 * store the output as a temporary file (tfile)... the 960 * protocol requires us to send the file size 961 */ 962 int i; 963 for (i = 0; i < stb.st_size; i += BUFSIZ) { 964 amt = BUFSIZ; 965 if (i + amt > stb.st_size) 966 amt = stb.st_size - i; 967 if (sizerr == 0 && read(f, buf, amt) != amt) { 968 sizerr = 1; 969 break; 970 } 971 if (write(ofd, buf, amt) != amt) { 972 (void) close(f); 973 return(REPRINT); 974 } 975 } 976 close(ofd); 977 close(f); 978 while ((i = wait(NULL)) > 0 && i != ofilter) 979 ; 980 ofilter = 0; 981 if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 982 openpr(); 983 return(ERROR); 984 } 985 f = tfd; 986 lseek(f,0,SEEK_SET); 987 closedpr = 1; 988 } 989 } 990 991 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 992 amt = strlen(buf); 993 for (i = 0; ; i++) { 994 if (write(pfd, buf, amt) != amt || 995 (resp = response()) < 0 || resp == '\1') { 996 (void) close(f); 997 if (tfd != -1 && type == '\3') { 998 tfd = -1; 999 unlink(tfile); 1000 if (closedpr) 1001 openpr(); 1002 } 1003 return(REPRINT); 1004 } else if (resp == '\0') 1005 break; 1006 if (i == 0) 1007 pstatus("no space on remote; waiting for queue to drain"); 1008 if (i == 10) 1009 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1010 printer, RM); 1011 sleep(5 * 60); 1012 } 1013 if (i) 1014 pstatus("sending to %s", RM); 1015 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1016 amt = BUFSIZ; 1017 if (i + amt > stb.st_size) 1018 amt = stb.st_size - i; 1019 if (sizerr == 0 && read(f, buf, amt) != amt) 1020 sizerr = 1; 1021 if (write(pfd, buf, amt) != amt) { 1022 (void) close(f); 1023 if (tfd != -1 && type == '\3') { 1024 tfd = -1; 1025 unlink(tfile); 1026 if (closedpr) 1027 openpr(); 1028 } 1029 return(REPRINT); 1030 } 1031 } 1032 1033 (void) close(f); 1034 if (tfd != -1 && type == '\3') { 1035 tfd = -1; 1036 unlink(tfile); 1037 } 1038 if (sizerr) { 1039 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 1040 /* tell recvjob to ignore this file */ 1041 (void) write(pfd, "\1", 1); 1042 if (closedpr) 1043 openpr(); 1044 return(ERROR); 1045 } 1046 if (write(pfd, "", 1) != 1 || response()) { 1047 if (closedpr) 1048 openpr(); 1049 return(REPRINT); 1050 } 1051 if (closedpr) 1052 openpr(); 1053 return(OK); 1054} 1055 1056/* 1057 * Check to make sure there have been no errors and that both programs 1058 * are in sync with eachother. 1059 * Return non-zero if the connection was lost. 1060 */ 1061static char 1062response() 1063{ 1064 char resp; 1065 1066 if (read(pfd, &resp, 1) != 1) { 1067 syslog(LOG_INFO, "%s: lost connection", printer); 1068 return(-1); 1069 } 1070 return(resp); 1071} 1072 1073/* 1074 * Banner printing stuff 1075 */ 1076static void 1077banner(name1, name2) 1078 char *name1, *name2; 1079{ 1080 time_t tvec; 1081 1082 time(&tvec); 1083 if (!SF && !tof) 1084 (void) write(ofd, FF, strlen(FF)); 1085 if (SB) { /* short banner only */ 1086 if (class[0]) { 1087 (void) write(ofd, class, strlen(class)); 1088 (void) write(ofd, ":", 1); 1089 } 1090 (void) write(ofd, name1, strlen(name1)); 1091 (void) write(ofd, " Job: ", 7); 1092 (void) write(ofd, name2, strlen(name2)); 1093 (void) write(ofd, " Date: ", 8); 1094 (void) write(ofd, ctime(&tvec), 24); 1095 (void) write(ofd, "\n", 1); 1096 } else { /* normal banner */ 1097 (void) write(ofd, "\n\n\n", 3); 1098 scan_out(ofd, name1, '\0'); 1099 (void) write(ofd, "\n\n", 2); 1100 scan_out(ofd, name2, '\0'); 1101 if (class[0]) { 1102 (void) write(ofd,"\n\n\n",3); 1103 scan_out(ofd, class, '\0'); 1104 } 1105 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1106 (void) write(ofd, name2, strlen(name2)); 1107 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1108 (void) write(ofd, ctime(&tvec), 24); 1109 (void) write(ofd, "\n", 1); 1110 } 1111 if (!SF) 1112 (void) write(ofd, FF, strlen(FF)); 1113 tof = 1; 1114} 1115 1116static char * 1117scnline(key, p, c) 1118 register int key; 1119 register char *p; 1120 int c; 1121{ 1122 register scnwidth; 1123 1124 for (scnwidth = WIDTH; --scnwidth;) { 1125 key <<= 1; 1126 *p++ = key & 0200 ? c : BACKGND; 1127 } 1128 return (p); 1129} 1130 1131#define TRC(q) (((q)-' ')&0177) 1132 1133static void 1134scan_out(scfd, scsp, dlm) 1135 int scfd, dlm; 1136 char *scsp; 1137{ 1138 register char *strp; 1139 register nchrs, j; 1140 char outbuf[LINELEN+1], *sp, c, cc; 1141 int d, scnhgt; 1142 1143 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1144 strp = &outbuf[0]; 1145 sp = scsp; 1146 for (nchrs = 0; ; ) { 1147 d = dropit(c = TRC(cc = *sp++)); 1148 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1149 for (j = WIDTH; --j;) 1150 *strp++ = BACKGND; 1151 else 1152 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 1153 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 1154 break; 1155 *strp++ = BACKGND; 1156 *strp++ = BACKGND; 1157 } 1158 while (*--strp == BACKGND && strp >= outbuf) 1159 ; 1160 strp++; 1161 *strp++ = '\n'; 1162 (void) write(scfd, outbuf, strp-outbuf); 1163 } 1164} 1165 1166static int 1167dropit(c) 1168 int c; 1169{ 1170 switch(c) { 1171 1172 case TRC('_'): 1173 case TRC(';'): 1174 case TRC(','): 1175 case TRC('g'): 1176 case TRC('j'): 1177 case TRC('p'): 1178 case TRC('q'): 1179 case TRC('y'): 1180 return (DROP); 1181 1182 default: 1183 return (0); 1184 } 1185} 1186 1187/* 1188 * sendmail --- 1189 * tell people about job completion 1190 */ 1191static void 1192sendmail(user, bombed) 1193 char *user; 1194 int bombed; 1195{ 1196 register int i; 1197 int dtablesize; 1198 int p[2], s; 1199 register char *cp; 1200 struct stat stb; 1201 FILE *fp; 1202 1203 pipe(p); 1204 if ((s = dofork(DORETURN)) == 0) { /* child */ 1205 dup2(p[0], 0); 1206 closelog(); 1207 for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++) 1208 (void) close(i); 1209 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1210 cp++; 1211 else 1212 cp = _PATH_SENDMAIL; 1213 execl(_PATH_SENDMAIL, cp, "-t", 0); 1214 exit(0); 1215 } else if (s > 0) { /* parent */ 1216 dup2(p[1], 1); 1217 printf("To: %s@%s\n", user, fromhost); 1218 printf("Subject: %s printer job \"%s\"\n", printer, 1219 *jobname ? jobname : "<unknown>"); 1220 printf("Reply-To: root@%s\n\n", host); 1221 printf("Your printer job "); 1222 if (*jobname) 1223 printf("(%s) ", jobname); 1224 switch (bombed) { 1225 case OK: 1226 printf("\ncompleted successfully\n"); 1227 cp = "OK"; 1228 break; 1229 default: 1230 case FATALERR: 1231 printf("\ncould not be printed\n"); 1232 cp = "FATALERR"; 1233 break; 1234 case NOACCT: 1235 printf("\ncould not be printed without an account on %s\n", host); 1236 cp = "NOACCT"; 1237 break; 1238 case FILTERERR: 1239 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1240 (fp = fopen(tempfile, "r")) == NULL) { 1241 printf("\nhad some errors and may not have printed\n"); 1242 break; 1243 } 1244 printf("\nhad the following errors and may not have printed:\n"); 1245 while ((i = getc(fp)) != EOF) 1246 putchar(i); 1247 (void) fclose(fp); 1248 cp = "FILTERERR"; 1249 break; 1250 case ACCESS: 1251 printf("\nwas not printed because it was not linked to the original file\n"); 1252 cp = "ACCESS"; 1253 } 1254 fflush(stdout); 1255 (void) close(1); 1256 } 1257 (void) close(p[0]); 1258 (void) close(p[1]); 1259 wait(NULL); 1260 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1261 user, *jobname ? jobname : "<unknown>", printer, cp); 1262} 1263 1264/* 1265 * dofork - fork with retries on failure 1266 */ 1267static int 1268dofork(action) 1269 int action; 1270{ 1271 register int i, pid; 1272 1273 for (i = 0; i < 20; i++) { 1274 if ((pid = fork()) < 0) { 1275 sleep((unsigned)(i*i)); 1276 continue; 1277 } 1278 /* 1279 * Child should run as daemon instead of root 1280 */ 1281 if (pid == 0) 1282 setuid(DU); 1283 return(pid); 1284 } 1285 syslog(LOG_ERR, "can't fork"); 1286 1287 switch (action) { 1288 case DORETURN: 1289 return (-1); 1290 default: 1291 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1292 /*FALL THRU*/ 1293 case DOABORT: 1294 exit(1); 1295 } 1296 /*NOTREACHED*/ 1297} 1298 1299/* 1300 * Kill child processes to abort current job. 1301 */ 1302static void 1303abortpr(signo) 1304 int signo; 1305{ 1306 (void) unlink(tempfile); 1307 kill(0, SIGINT); 1308 if (ofilter > 0) 1309 kill(ofilter, SIGCONT); 1310 while (wait(NULL) > 0) 1311 ; 1312 if (ofilter > 0 && tfd != -1) 1313 unlink(tfile); 1314 exit(0); 1315} 1316 1317static void 1318init() 1319{ 1320 int status; 1321 char *s; 1322 1323 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1324 syslog(LOG_ERR, "can't open printer description file"); 1325 exit(1); 1326 } else if (status == -1) { 1327 syslog(LOG_ERR, "unknown printer: %s", printer); 1328 exit(1); 1329 } else if (status == -3) 1330 fatal("potential reference loop detected in printcap file"); 1331 1332 if (cgetstr(bp, "lp", &LP) == -1) 1333 LP = _PATH_DEFDEVLP; 1334 if (cgetstr(bp, "rp", &RP) == -1) 1335 RP = DEFLP; 1336 if (cgetstr(bp, "lo", &LO) == -1) 1337 LO = DEFLOCK; 1338 if (cgetstr(bp, "st", &ST) == -1) 1339 ST = DEFSTAT; 1340 if (cgetstr(bp, "lf", &LF) == -1) 1341 LF = _PATH_CONSOLE; 1342 if (cgetstr(bp, "sd", &SD) == -1) 1343 SD = _PATH_DEFSPOOL; 1344 if (cgetnum(bp, "du", &DU) < 0) 1345 DU = DEFUID; 1346 if (cgetstr(bp,"ff", &FF) == -1) 1347 FF = DEFFF; 1348 if (cgetnum(bp, "pw", &PW) < 0) 1349 PW = DEFWIDTH; 1350 sprintf(&width[2], "%ld", PW); 1351 if (cgetnum(bp, "pl", &PL) < 0) 1352 PL = DEFLENGTH;
| 120static void banner __P((char *, char *)); 121static int dofork __P((int)); 122static int dropit __P((int)); 123static void init __P((void)); 124static void openpr __P((void)); 125static void opennet __P((char *)); 126static void opentty __P((void)); 127static void openrem __P((void)); 128static int print __P((int, char *)); 129static int printit __P((char *)); 130static void pstatus __P((const char *, ...)); 131static char response __P((void)); 132static void scan_out __P((int, char *, int)); 133static char *scnline __P((int, char *, int)); 134static int sendfile __P((int, char *, char)); 135static int sendit __P((char *)); 136static void sendmail __P((char *, int)); 137static void setty __P((void)); 138 139void 140printjob() 141{ 142 struct stat stb; 143 register struct queue *q, **qp; 144 struct queue **queue; 145 register int i, nitems; 146 off_t pidoff; 147 int errcnt, count = 0; 148 149 init(); /* set up capabilities */ 150 (void) write(1, "", 1); /* ack that daemon is started */ 151 (void) close(2); /* set up log file */ 152 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 153 syslog(LOG_ERR, "%s: %m", LF); 154 (void) open(_PATH_DEVNULL, O_WRONLY); 155 } 156 setgid(getegid()); 157 pid = getpid(); /* for use with lprm */ 158 setpgrp(0, pid); 159 signal(SIGHUP, abortpr); 160 signal(SIGINT, abortpr); 161 signal(SIGQUIT, abortpr); 162 signal(SIGTERM, abortpr); 163 164 (void) mktemp(tempfile); 165 166 /* 167 * uses short form file names 168 */ 169 if (chdir(SD) < 0) { 170 syslog(LOG_ERR, "%s: %m", SD); 171 exit(1); 172 } 173 if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 174 exit(0); /* printing disabled */ 175 lfd = open(LO, O_WRONLY|O_CREAT, 0644); 176 if (lfd < 0) { 177 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 178 exit(1); 179 } 180 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 181 if (errno == EWOULDBLOCK) /* active deamon present */ 182 exit(0); 183 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 184 exit(1); 185 } 186 ftruncate(lfd, 0); 187 /* 188 * write process id for others to know 189 */ 190 sprintf(line, "%u\n", pid); 191 pidoff = i = strlen(line); 192 if (write(lfd, line, i) != i) { 193 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 194 exit(1); 195 } 196 /* 197 * search the spool directory for work and sort by queue order. 198 */ 199 if ((nitems = getq(&queue)) < 0) { 200 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 201 exit(1); 202 } 203 if (nitems == 0) /* no work to do */ 204 exit(0); 205 if (stb.st_mode & 01) { /* reset queue flag */ 206 if (fchmod(lfd, stb.st_mode & 0776) < 0) 207 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 208 } 209 openpr(); /* open printer or remote */ 210again: 211 /* 212 * we found something to do now do it -- 213 * write the name of the current control file into the lock file 214 * so the spool queue program can tell what we're working on 215 */ 216 for (qp = queue; nitems--; free((char *) q)) { 217 q = *qp++; 218 if (stat(q->q_name, &stb) < 0) 219 continue; 220 errcnt = 0; 221 restart: 222 (void) lseek(lfd, pidoff, 0); 223 (void) snprintf(line, sizeof(line), "%s\n", q->q_name); 224 i = strlen(line); 225 if (write(lfd, line, i) != i) 226 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 227 if (!remote) 228 i = printit(q->q_name); 229 else 230 i = sendit(q->q_name); 231 /* 232 * Check to see if we are supposed to stop printing or 233 * if we are to rebuild the queue. 234 */ 235 if (fstat(lfd, &stb) == 0) { 236 /* stop printing before starting next job? */ 237 if (stb.st_mode & 0100) 238 goto done; 239 /* rebuild queue (after lpc topq) */ 240 if (stb.st_mode & 01) { 241 for (free((char *) q); nitems--; free((char *) q)) 242 q = *qp++; 243 if (fchmod(lfd, stb.st_mode & 0776) < 0) 244 syslog(LOG_WARNING, "%s: %s: %m", 245 printer, LO); 246 break; 247 } 248 } 249 if (i == OK) /* file ok and printed */ 250 count++; 251 else if (i == REPRINT && ++errcnt < 5) { 252 /* try reprinting the job */ 253 syslog(LOG_INFO, "restarting %s", printer); 254 if (ofilter > 0) { 255 kill(ofilter, SIGCONT); /* to be sure */ 256 (void) close(ofd); 257 while ((i = wait(NULL)) > 0 && i != ofilter) 258 ; 259 ofilter = 0; 260 } 261 (void) close(pfd); /* close printer */ 262 if (ftruncate(lfd, pidoff) < 0) 263 syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 264 openpr(); /* try to reopen printer */ 265 goto restart; 266 } else { 267 syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 268 remote ? "sent to remote host" : "printed", q->q_name); 269 if (i == REPRINT) { 270 /* ensure we don't attempt this job again */ 271 (void) unlink(q->q_name); 272 q->q_name[0] = 'd'; 273 (void) unlink(q->q_name); 274 if (logname[0]) 275 sendmail(logname, FATALERR); 276 } 277 } 278 } 279 free((char *) queue); 280 /* 281 * search the spool directory for more work. 282 */ 283 if ((nitems = getq(&queue)) < 0) { 284 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 285 exit(1); 286 } 287 if (nitems == 0) { /* no more work to do */ 288 done: 289 if (count > 0) { /* Files actually printed */ 290 if (!SF && !tof) 291 (void) write(ofd, FF, strlen(FF)); 292 if (TR != NULL) /* output trailer */ 293 (void) write(ofd, TR, strlen(TR)); 294 } 295 (void) close(ofd); 296 (void) wait(NULL); 297 (void) unlink(tempfile); 298 exit(0); 299 } 300 goto again; 301} 302 303char fonts[4][50]; /* fonts for troff */ 304 305char ifonts[4][40] = { 306 _PATH_VFONTR, 307 _PATH_VFONTI, 308 _PATH_VFONTB, 309 _PATH_VFONTS, 310}; 311 312/* 313 * The remaining part is the reading of the control file (cf) 314 * and performing the various actions. 315 */ 316static int 317printit(file) 318 char *file; 319{ 320 register int i; 321 char *cp; 322 int bombed = OK; 323 324 /* 325 * open control file; ignore if no longer there. 326 */ 327 if ((cfp = fopen(file, "r")) == NULL) { 328 syslog(LOG_INFO, "%s: %s: %m", printer, file); 329 return(OK); 330 } 331 /* 332 * Reset troff fonts. 333 */ 334 for (i = 0; i < 4; i++) 335 strcpy(fonts[i], ifonts[i]); 336 sprintf(&width[2], "%ld", PW); 337 strcpy(indent+2, "0"); 338 339 /* 340 * read the control file for work to do 341 * 342 * file format -- first character in the line is a command 343 * rest of the line is the argument. 344 * valid commands are: 345 * 346 * S -- "stat info" for symbolic link protection 347 * J -- "job name" on banner page 348 * C -- "class name" on banner page 349 * L -- "literal" user's name to print on banner 350 * T -- "title" for pr 351 * H -- "host name" of machine where lpr was done 352 * P -- "person" user's login name 353 * I -- "indent" amount to indent output 354 * R -- laser dpi "resolution" 355 * f -- "file name" name of text file to print 356 * l -- "file name" text file with control chars 357 * p -- "file name" text file to print with pr(1) 358 * t -- "file name" troff(1) file to print 359 * n -- "file name" ditroff(1) file to print 360 * d -- "file name" dvi file to print 361 * g -- "file name" plot(1G) file to print 362 * v -- "file name" plain raster file to print 363 * c -- "file name" cifplot file to print 364 * 1 -- "R font file" for troff 365 * 2 -- "I font file" for troff 366 * 3 -- "B font file" for troff 367 * 4 -- "S font file" for troff 368 * N -- "name" of file (used by lpq) 369 * U -- "unlink" name of file to remove 370 * (after we print it. (Pass 2 only)). 371 * M -- "mail" to user when done printing 372 * 373 * getline reads a line and expands tabs to blanks 374 */ 375 376 /* pass 1 */ 377 378 while (getline(cfp)) 379 switch (line[0]) { 380 case 'H': 381 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 382 fromhost[sizeof(fromhost) - 1] = '\0'; 383 if (class[0] == '\0') { 384 strncpy(class, line+1, sizeof(class) - 1); 385 class[sizeof(class) - 1] = '\0'; 386 } 387 continue; 388 389 case 'P': 390 strncpy(logname, line+1, sizeof(logname) - 1); 391 logname[sizeof(logname) - 1] = '\0'; 392 if (RS) { /* restricted */ 393 if (getpwnam(logname) == NULL) { 394 bombed = NOACCT; 395 sendmail(line+1, bombed); 396 goto pass2; 397 } 398 } 399 continue; 400 401 case 'S': 402 cp = line+1; 403 i = 0; 404 while (*cp >= '0' && *cp <= '9') 405 i = i * 10 + (*cp++ - '0'); 406 fdev = i; 407 cp++; 408 i = 0; 409 while (*cp >= '0' && *cp <= '9') 410 i = i * 10 + (*cp++ - '0'); 411 fino = i; 412 continue; 413 414 case 'J': 415 if (line[1] != '\0') { 416 strncpy(jobname, line+1, sizeof(jobname) - 1); 417 jobname[sizeof(jobname) - 1] = '\0'; 418 } else 419 strcpy(jobname, " "); 420 continue; 421 422 case 'C': 423 if (line[1] != '\0') 424 strncpy(class, line+1, sizeof(class) - 1); 425 else if (class[0] == '\0') 426 gethostname(class, sizeof(class)); 427 class[sizeof(class) - 1] = '\0'; 428 continue; 429 430 case 'T': /* header title for pr */ 431 strncpy(title, line+1, sizeof(title) - 1); 432 title[sizeof(title) - 1] = '\0'; 433 continue; 434 435 case 'L': /* identification line */ 436 if (!SH && !HL) 437 banner(line+1, jobname); 438 continue; 439 440 case '1': /* troff fonts */ 441 case '2': 442 case '3': 443 case '4': 444 if (line[1] != '\0') { 445 strncpy(fonts[line[0]-'1'], line+1, 446 50-1); 447 fonts[line[0]-'1'][50-1] = '\0'; 448 } 449 continue; 450 451 case 'W': /* page width */ 452 strncpy(width+2, line+1, sizeof(width) - 3); 453 width[2+sizeof(width) - 3] = '\0'; 454 continue; 455 456 case 'I': /* indent amount */ 457 strncpy(indent+2, line+1, sizeof(indent) - 3); 458 indent[2+sizeof(indent) - 3] = '\0'; 459 continue; 460 461 default: /* some file to print */ 462 switch (i = print(line[0], line+1)) { 463 case ERROR: 464 if (bombed == OK) 465 bombed = FATALERR; 466 break; 467 case REPRINT: 468 (void) fclose(cfp); 469 return(REPRINT); 470 case FILTERERR: 471 case ACCESS: 472 bombed = i; 473 sendmail(logname, bombed); 474 } 475 title[0] = '\0'; 476 continue; 477 478 case 'N': 479 case 'U': 480 case 'M': 481 case 'R': 482 continue; 483 } 484 485 /* pass 2 */ 486 487pass2: 488 fseek(cfp, 0L, 0); 489 while (getline(cfp)) 490 switch (line[0]) { 491 case 'L': /* identification line */ 492 if (!SH && HL) 493 banner(line+1, jobname); 494 continue; 495 496 case 'M': 497 if (bombed < NOACCT) /* already sent if >= NOACCT */ 498 sendmail(line+1, bombed); 499 continue; 500 501 case 'U': 502 if (strchr(line+1, '/')) 503 continue; 504 (void) unlink(line+1); 505 } 506 /* 507 * clean-up in case another control file exists 508 */ 509 (void) fclose(cfp); 510 (void) unlink(file); 511 return(bombed == OK ? OK : ERROR); 512} 513 514/* 515 * Print a file. 516 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 517 * Return -1 if a non-recoverable error occured, 518 * 2 if the filter detected some errors (but printed the job anyway), 519 * 1 if we should try to reprint this job and 520 * 0 if all is well. 521 * Note: all filters take stdin as the file, stdout as the printer, 522 * stderr as the log file, and must not ignore SIGINT. 523 */ 524static int 525print(format, file) 526 int format; 527 char *file; 528{ 529 register int n; 530 register char *prog; 531 int dtablesize, fi, fo; 532 FILE *fp; 533 char *av[15], buf[BUFSIZ]; 534 int pid, p[2], stopped = 0; 535 union wait status; 536 struct stat stb; 537 538 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 539 return(ERROR); 540 /* 541 * Check to see if data file is a symbolic link. If so, it should 542 * still point to the same file or someone is trying to print 543 * something he shouldn't. 544 */ 545 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 546 (stb.st_dev != fdev || stb.st_ino != fino)) 547 return(ACCESS); 548 if (!SF && !tof) { /* start on a fresh page */ 549 (void) write(ofd, FF, strlen(FF)); 550 tof = 1; 551 } 552 if (IF == NULL && (format == 'f' || format == 'l')) { 553 tof = 0; 554 while ((n = read(fi, buf, BUFSIZ)) > 0) 555 if (write(ofd, buf, n) != n) { 556 (void) close(fi); 557 return(REPRINT); 558 } 559 (void) close(fi); 560 return(OK); 561 } 562 switch (format) { 563 case 'p': /* print file using 'pr' */ 564 if (IF == NULL) { /* use output filter */ 565 prog = _PATH_PR; 566 av[0] = "pr"; 567 av[1] = width; 568 av[2] = length; 569 av[3] = "-h"; 570 av[4] = *title ? title : " "; 571 av[5] = "-F"; 572 av[6] = 0; 573 fo = ofd; 574 goto start; 575 } 576 pipe(p); 577 if ((prchild = dofork(DORETURN)) == 0) { /* child */ 578 dup2(fi, 0); /* file is stdin */ 579 dup2(p[1], 1); /* pipe is stdout */ 580 closelog(); 581 for (n = 3, dtablesize = getdtablesize(); 582 n < dtablesize; n++) 583 (void) close(n); 584 execl(_PATH_PR, "pr", width, length, 585 "-h", *title ? title : " ", "-F", 0); 586 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 587 exit(2); 588 } 589 (void) close(p[1]); /* close output side */ 590 (void) close(fi); 591 if (prchild < 0) { 592 prchild = 0; 593 (void) close(p[0]); 594 return(ERROR); 595 } 596 fi = p[0]; /* use pipe for input */ 597 case 'f': /* print plain text file */ 598 prog = IF; 599 av[1] = width; 600 av[2] = length; 601 av[3] = indent; 602 n = 4; 603 break; 604 case 'l': /* like 'f' but pass control characters */ 605 prog = IF; 606 av[1] = "-c"; 607 av[2] = width; 608 av[3] = length; 609 av[4] = indent; 610 n = 5; 611 break; 612 case 'r': /* print a fortran text file */ 613 prog = RF; 614 av[1] = width; 615 av[2] = length; 616 n = 3; 617 break; 618 case 't': /* print troff output */ 619 case 'n': /* print ditroff output */ 620 case 'd': /* print tex output */ 621 (void) unlink(".railmag"); 622 if ((fo = creat(".railmag", FILMOD)) < 0) { 623 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 624 (void) unlink(".railmag"); 625 } else { 626 for (n = 0; n < 4; n++) { 627 if (fonts[n][0] != '/') 628 (void) write(fo, _PATH_VFONT, 629 sizeof(_PATH_VFONT) - 1); 630 (void) write(fo, fonts[n], strlen(fonts[n])); 631 (void) write(fo, "\n", 1); 632 } 633 (void) close(fo); 634 } 635 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 636 av[1] = pxwidth; 637 av[2] = pxlength; 638 n = 3; 639 break; 640 case 'c': /* print cifplot output */ 641 prog = CF; 642 av[1] = pxwidth; 643 av[2] = pxlength; 644 n = 3; 645 break; 646 case 'g': /* print plot(1G) output */ 647 prog = GF; 648 av[1] = pxwidth; 649 av[2] = pxlength; 650 n = 3; 651 break; 652 case 'v': /* print raster output */ 653 prog = VF; 654 av[1] = pxwidth; 655 av[2] = pxlength; 656 n = 3; 657 break; 658 default: 659 (void) close(fi); 660 syslog(LOG_ERR, "%s: illegal format character '%c'", 661 printer, format); 662 return(ERROR); 663 } 664 if (prog == NULL) { 665 (void) close(fi); 666 syslog(LOG_ERR, 667 "%s: no filter found in printcap for format character '%c'", 668 printer, format); 669 return(ERROR); 670 } 671 if ((av[0] = strrchr(prog, '/')) != NULL) 672 av[0]++; 673 else 674 av[0] = prog; 675 av[n++] = "-n"; 676 av[n++] = logname; 677 av[n++] = "-h"; 678 av[n++] = fromhost; 679 av[n++] = AF; 680 av[n] = 0; 681 fo = pfd; 682 if (ofilter > 0) { /* stop output filter */ 683 write(ofd, "\031\1", 2); 684 while ((pid = 685 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 686 ; 687 if (status.w_stopval != WSTOPPED) { 688 (void) close(fi); 689 syslog(LOG_WARNING, 690 "%s: output filter died (retcode=%d termsig=%d)", 691 printer, status.w_retcode, status.w_termsig); 692 return(REPRINT); 693 } 694 stopped++; 695 } 696start: 697 if ((child = dofork(DORETURN)) == 0) { /* child */ 698 dup2(fi, 0); 699 dup2(fo, 1); 700 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 701 if (n >= 0) 702 dup2(n, 2); 703 closelog(); 704 for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++) 705 (void) close(n); 706 execv(prog, av); 707 syslog(LOG_ERR, "cannot execv %s", prog); 708 exit(2); 709 } 710 (void) close(fi); 711 if (child < 0) 712 status.w_retcode = 100; 713 else 714 while ((pid = wait((int *)&status)) > 0 && pid != child) 715 ; 716 child = 0; 717 prchild = 0; 718 if (stopped) { /* restart output filter */ 719 if (kill(ofilter, SIGCONT) < 0) { 720 syslog(LOG_ERR, "cannot restart output filter"); 721 exit(1); 722 } 723 } 724 tof = 0; 725 726 /* Copy filter output to "lf" logfile */ 727 if ((fp = fopen(tempfile, "r"))) { 728 while (fgets(buf, sizeof(buf), fp)) 729 fputs(buf, stderr); 730 fclose(fp); 731 } 732 733 if (!WIFEXITED(status)) { 734 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 735 printer, format, status.w_termsig); 736 return(ERROR); 737 } 738 switch (status.w_retcode) { 739 case 0: 740 tof = 1; 741 return(OK); 742 case 1: 743 return(REPRINT); 744 case 2: 745 return(ERROR); 746 default: 747 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 748 printer, format, status.w_retcode); 749 return(FILTERERR); 750 } 751} 752 753/* 754 * Send the daemon control file (cf) and any data files. 755 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 756 * 0 if all is well. 757 */ 758static int 759sendit(file) 760 char *file; 761{ 762 register int i, err = OK; 763 char *cp, last[BUFSIZ]; 764 765 /* 766 * open control file 767 */ 768 if ((cfp = fopen(file, "r")) == NULL) 769 return(OK); 770 /* 771 * read the control file for work to do 772 * 773 * file format -- first character in the line is a command 774 * rest of the line is the argument. 775 * commands of interest are: 776 * 777 * a-z -- "file name" name of file to print 778 * U -- "unlink" name of file to remove 779 * (after we print it. (Pass 2 only)). 780 */ 781 782 /* 783 * pass 1 784 */ 785 while (getline(cfp)) { 786 again: 787 if (line[0] == 'S') { 788 cp = line+1; 789 i = 0; 790 while (*cp >= '0' && *cp <= '9') 791 i = i * 10 + (*cp++ - '0'); 792 fdev = i; 793 cp++; 794 i = 0; 795 while (*cp >= '0' && *cp <= '9') 796 i = i * 10 + (*cp++ - '0'); 797 fino = i; 798 } else if (line[0] == 'H') { 799 strcpy(fromhost, line+1); 800 if (class[0] == '\0') 801 strncpy(class, line+1, sizeof(class) - 1); 802 } else if (line[0] == 'P') { 803 strncpy(logname, line+1, sizeof(logname) - 1); 804 if (RS) { /* restricted */ 805 if (getpwnam(logname) == NULL) { 806 sendmail(line+1, NOACCT); 807 err = ERROR; 808 break; 809 } 810 } 811 } else if (line[0] == 'I') { 812 strncpy(indent+2, line+1, sizeof(indent) - 3); 813 } else if (line[0] >= 'a' && line[0] <= 'z') { 814 strcpy(last, line); 815 while (i = getline(cfp)) 816 if (strcmp(last, line)) 817 break; 818 switch (sendfile('\3', last+1, *last)) { 819 case OK: 820 if (i) 821 goto again; 822 break; 823 case REPRINT: 824 (void) fclose(cfp); 825 return(REPRINT); 826 case ACCESS: 827 sendmail(logname, ACCESS); 828 case ERROR: 829 err = ERROR; 830 } 831 break; 832 } 833 } 834 if (err == OK && sendfile('\2', file, '\0') > 0) { 835 (void) fclose(cfp); 836 return(REPRINT); 837 } 838 /* 839 * pass 2 840 */ 841 fseek(cfp, 0L, 0); 842 while (getline(cfp)) 843 if (line[0] == 'U' && !strchr(line+1, '/')) 844 (void) unlink(line+1); 845 /* 846 * clean-up in case another control file exists 847 */ 848 (void) fclose(cfp); 849 (void) unlink(file); 850 return(err); 851} 852 853/* 854 * Send a data file to the remote machine and spool it. 855 * Return positive if we should try resending. 856 */ 857static int 858sendfile(type, file, format) 859 int type; 860 char *file; 861 char format; 862{ 863 register int f, i, amt; 864 struct stat stb; 865 char buf[BUFSIZ]; 866 int sizerr, resp, closedpr; 867 868 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 869 return(ERROR); 870 /* 871 * Check to see if data file is a symbolic link. If so, it should 872 * still point to the same file or someone is trying to print something 873 * he shouldn't. 874 */ 875 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 876 (stb.st_dev != fdev || stb.st_ino != fino)) 877 return(ACCESS); 878 879 sizerr = 0; 880 closedpr = 0; 881 if (type == '\3') { 882 if (IF) { 883 /* 884 * We're sending something with an ifilter, we have to 885 * run the ifilter and store the output as a 886 * temporary file (tfile)... the protocol requires us 887 * to send the file size 888 */ 889 char *av[15]; 890 int n; 891 int nfd; 892 int ifilter; 893 union wait status; 894 895 strcpy(tfile,TFILENAME); 896 if ((tfd = mkstemp(tfile)) == -1) { 897 syslog(LOG_ERR, "mkstemp: %m"); 898 return(ERROR); 899 } 900 if ((av[0] = strrchr(IF, '/')) == NULL) 901 av[0] = IF; 902 else 903 av[0]++; 904 if (format == 'l') 905 av[n=1] = "-c"; 906 else 907 n = 0; 908 av[++n] = width; 909 av[++n] = length; 910 av[++n] = indent; 911 av[++n] = "-n"; 912 av[++n] = logname; 913 av[++n] = "-h"; 914 av[++n] = fromhost; 915 av[++n] = AF; 916 av[++n] = 0; 917 if ((ifilter = dofork(DORETURN)) == 0) { /* child */ 918 dup2(f, 0); 919 dup2(tfd, 1); 920 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 921 if (n >= 0) 922 dup2(n, 2); 923 closelog(); 924 for (n = 3, nfd = getdtablesize(); n < nfd; n++) 925 (void) close(n); 926 execv(IF, av); 927 syslog(LOG_ERR, "cannot execv %s", IF); 928 exit(2); 929 } 930 (void) close(f); 931 if (ifilter < 0) 932 status.w_retcode = 100; 933 else 934 while ((pid = wait((int *)&status)) > 0 && 935 pid != ifilter) 936 ; 937 switch (status.w_retcode) { 938 case 0: 939 break; 940 case 1: 941 unlink(tfile); 942 return(REPRINT); 943 case 2: 944 unlink(tfile); 945 return(ERROR); 946 default: 947 syslog(LOG_WARNING, "%s: filter '%c' exited" 948 " (retcode=%d)", 949 printer, format, status.w_retcode); 950 unlink(tfile); 951 return(FILTERERR); 952 } 953 if (fstat(tfd, &stb) < 0) /* the size of tfile */ 954 return(ERROR); 955 f = tfd; 956 lseek(f,0,SEEK_SET); 957 } else if (ofilter) { 958 /* 959 * We're sending something with an ofilter, we have to 960 * store the output as a temporary file (tfile)... the 961 * protocol requires us to send the file size 962 */ 963 int i; 964 for (i = 0; i < stb.st_size; i += BUFSIZ) { 965 amt = BUFSIZ; 966 if (i + amt > stb.st_size) 967 amt = stb.st_size - i; 968 if (sizerr == 0 && read(f, buf, amt) != amt) { 969 sizerr = 1; 970 break; 971 } 972 if (write(ofd, buf, amt) != amt) { 973 (void) close(f); 974 return(REPRINT); 975 } 976 } 977 close(ofd); 978 close(f); 979 while ((i = wait(NULL)) > 0 && i != ofilter) 980 ; 981 ofilter = 0; 982 if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 983 openpr(); 984 return(ERROR); 985 } 986 f = tfd; 987 lseek(f,0,SEEK_SET); 988 closedpr = 1; 989 } 990 } 991 992 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 993 amt = strlen(buf); 994 for (i = 0; ; i++) { 995 if (write(pfd, buf, amt) != amt || 996 (resp = response()) < 0 || resp == '\1') { 997 (void) close(f); 998 if (tfd != -1 && type == '\3') { 999 tfd = -1; 1000 unlink(tfile); 1001 if (closedpr) 1002 openpr(); 1003 } 1004 return(REPRINT); 1005 } else if (resp == '\0') 1006 break; 1007 if (i == 0) 1008 pstatus("no space on remote; waiting for queue to drain"); 1009 if (i == 10) 1010 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1011 printer, RM); 1012 sleep(5 * 60); 1013 } 1014 if (i) 1015 pstatus("sending to %s", RM); 1016 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1017 amt = BUFSIZ; 1018 if (i + amt > stb.st_size) 1019 amt = stb.st_size - i; 1020 if (sizerr == 0 && read(f, buf, amt) != amt) 1021 sizerr = 1; 1022 if (write(pfd, buf, amt) != amt) { 1023 (void) close(f); 1024 if (tfd != -1 && type == '\3') { 1025 tfd = -1; 1026 unlink(tfile); 1027 if (closedpr) 1028 openpr(); 1029 } 1030 return(REPRINT); 1031 } 1032 } 1033 1034 (void) close(f); 1035 if (tfd != -1 && type == '\3') { 1036 tfd = -1; 1037 unlink(tfile); 1038 } 1039 if (sizerr) { 1040 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 1041 /* tell recvjob to ignore this file */ 1042 (void) write(pfd, "\1", 1); 1043 if (closedpr) 1044 openpr(); 1045 return(ERROR); 1046 } 1047 if (write(pfd, "", 1) != 1 || response()) { 1048 if (closedpr) 1049 openpr(); 1050 return(REPRINT); 1051 } 1052 if (closedpr) 1053 openpr(); 1054 return(OK); 1055} 1056 1057/* 1058 * Check to make sure there have been no errors and that both programs 1059 * are in sync with eachother. 1060 * Return non-zero if the connection was lost. 1061 */ 1062static char 1063response() 1064{ 1065 char resp; 1066 1067 if (read(pfd, &resp, 1) != 1) { 1068 syslog(LOG_INFO, "%s: lost connection", printer); 1069 return(-1); 1070 } 1071 return(resp); 1072} 1073 1074/* 1075 * Banner printing stuff 1076 */ 1077static void 1078banner(name1, name2) 1079 char *name1, *name2; 1080{ 1081 time_t tvec; 1082 1083 time(&tvec); 1084 if (!SF && !tof) 1085 (void) write(ofd, FF, strlen(FF)); 1086 if (SB) { /* short banner only */ 1087 if (class[0]) { 1088 (void) write(ofd, class, strlen(class)); 1089 (void) write(ofd, ":", 1); 1090 } 1091 (void) write(ofd, name1, strlen(name1)); 1092 (void) write(ofd, " Job: ", 7); 1093 (void) write(ofd, name2, strlen(name2)); 1094 (void) write(ofd, " Date: ", 8); 1095 (void) write(ofd, ctime(&tvec), 24); 1096 (void) write(ofd, "\n", 1); 1097 } else { /* normal banner */ 1098 (void) write(ofd, "\n\n\n", 3); 1099 scan_out(ofd, name1, '\0'); 1100 (void) write(ofd, "\n\n", 2); 1101 scan_out(ofd, name2, '\0'); 1102 if (class[0]) { 1103 (void) write(ofd,"\n\n\n",3); 1104 scan_out(ofd, class, '\0'); 1105 } 1106 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1107 (void) write(ofd, name2, strlen(name2)); 1108 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1109 (void) write(ofd, ctime(&tvec), 24); 1110 (void) write(ofd, "\n", 1); 1111 } 1112 if (!SF) 1113 (void) write(ofd, FF, strlen(FF)); 1114 tof = 1; 1115} 1116 1117static char * 1118scnline(key, p, c) 1119 register int key; 1120 register char *p; 1121 int c; 1122{ 1123 register scnwidth; 1124 1125 for (scnwidth = WIDTH; --scnwidth;) { 1126 key <<= 1; 1127 *p++ = key & 0200 ? c : BACKGND; 1128 } 1129 return (p); 1130} 1131 1132#define TRC(q) (((q)-' ')&0177) 1133 1134static void 1135scan_out(scfd, scsp, dlm) 1136 int scfd, dlm; 1137 char *scsp; 1138{ 1139 register char *strp; 1140 register nchrs, j; 1141 char outbuf[LINELEN+1], *sp, c, cc; 1142 int d, scnhgt; 1143 1144 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1145 strp = &outbuf[0]; 1146 sp = scsp; 1147 for (nchrs = 0; ; ) { 1148 d = dropit(c = TRC(cc = *sp++)); 1149 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1150 for (j = WIDTH; --j;) 1151 *strp++ = BACKGND; 1152 else 1153 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 1154 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 1155 break; 1156 *strp++ = BACKGND; 1157 *strp++ = BACKGND; 1158 } 1159 while (*--strp == BACKGND && strp >= outbuf) 1160 ; 1161 strp++; 1162 *strp++ = '\n'; 1163 (void) write(scfd, outbuf, strp-outbuf); 1164 } 1165} 1166 1167static int 1168dropit(c) 1169 int c; 1170{ 1171 switch(c) { 1172 1173 case TRC('_'): 1174 case TRC(';'): 1175 case TRC(','): 1176 case TRC('g'): 1177 case TRC('j'): 1178 case TRC('p'): 1179 case TRC('q'): 1180 case TRC('y'): 1181 return (DROP); 1182 1183 default: 1184 return (0); 1185 } 1186} 1187 1188/* 1189 * sendmail --- 1190 * tell people about job completion 1191 */ 1192static void 1193sendmail(user, bombed) 1194 char *user; 1195 int bombed; 1196{ 1197 register int i; 1198 int dtablesize; 1199 int p[2], s; 1200 register char *cp; 1201 struct stat stb; 1202 FILE *fp; 1203 1204 pipe(p); 1205 if ((s = dofork(DORETURN)) == 0) { /* child */ 1206 dup2(p[0], 0); 1207 closelog(); 1208 for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++) 1209 (void) close(i); 1210 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1211 cp++; 1212 else 1213 cp = _PATH_SENDMAIL; 1214 execl(_PATH_SENDMAIL, cp, "-t", 0); 1215 exit(0); 1216 } else if (s > 0) { /* parent */ 1217 dup2(p[1], 1); 1218 printf("To: %s@%s\n", user, fromhost); 1219 printf("Subject: %s printer job \"%s\"\n", printer, 1220 *jobname ? jobname : "<unknown>"); 1221 printf("Reply-To: root@%s\n\n", host); 1222 printf("Your printer job "); 1223 if (*jobname) 1224 printf("(%s) ", jobname); 1225 switch (bombed) { 1226 case OK: 1227 printf("\ncompleted successfully\n"); 1228 cp = "OK"; 1229 break; 1230 default: 1231 case FATALERR: 1232 printf("\ncould not be printed\n"); 1233 cp = "FATALERR"; 1234 break; 1235 case NOACCT: 1236 printf("\ncould not be printed without an account on %s\n", host); 1237 cp = "NOACCT"; 1238 break; 1239 case FILTERERR: 1240 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1241 (fp = fopen(tempfile, "r")) == NULL) { 1242 printf("\nhad some errors and may not have printed\n"); 1243 break; 1244 } 1245 printf("\nhad the following errors and may not have printed:\n"); 1246 while ((i = getc(fp)) != EOF) 1247 putchar(i); 1248 (void) fclose(fp); 1249 cp = "FILTERERR"; 1250 break; 1251 case ACCESS: 1252 printf("\nwas not printed because it was not linked to the original file\n"); 1253 cp = "ACCESS"; 1254 } 1255 fflush(stdout); 1256 (void) close(1); 1257 } 1258 (void) close(p[0]); 1259 (void) close(p[1]); 1260 wait(NULL); 1261 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1262 user, *jobname ? jobname : "<unknown>", printer, cp); 1263} 1264 1265/* 1266 * dofork - fork with retries on failure 1267 */ 1268static int 1269dofork(action) 1270 int action; 1271{ 1272 register int i, pid; 1273 1274 for (i = 0; i < 20; i++) { 1275 if ((pid = fork()) < 0) { 1276 sleep((unsigned)(i*i)); 1277 continue; 1278 } 1279 /* 1280 * Child should run as daemon instead of root 1281 */ 1282 if (pid == 0) 1283 setuid(DU); 1284 return(pid); 1285 } 1286 syslog(LOG_ERR, "can't fork"); 1287 1288 switch (action) { 1289 case DORETURN: 1290 return (-1); 1291 default: 1292 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1293 /*FALL THRU*/ 1294 case DOABORT: 1295 exit(1); 1296 } 1297 /*NOTREACHED*/ 1298} 1299 1300/* 1301 * Kill child processes to abort current job. 1302 */ 1303static void 1304abortpr(signo) 1305 int signo; 1306{ 1307 (void) unlink(tempfile); 1308 kill(0, SIGINT); 1309 if (ofilter > 0) 1310 kill(ofilter, SIGCONT); 1311 while (wait(NULL) > 0) 1312 ; 1313 if (ofilter > 0 && tfd != -1) 1314 unlink(tfile); 1315 exit(0); 1316} 1317 1318static void 1319init() 1320{ 1321 int status; 1322 char *s; 1323 1324 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1325 syslog(LOG_ERR, "can't open printer description file"); 1326 exit(1); 1327 } else if (status == -1) { 1328 syslog(LOG_ERR, "unknown printer: %s", printer); 1329 exit(1); 1330 } else if (status == -3) 1331 fatal("potential reference loop detected in printcap file"); 1332 1333 if (cgetstr(bp, "lp", &LP) == -1) 1334 LP = _PATH_DEFDEVLP; 1335 if (cgetstr(bp, "rp", &RP) == -1) 1336 RP = DEFLP; 1337 if (cgetstr(bp, "lo", &LO) == -1) 1338 LO = DEFLOCK; 1339 if (cgetstr(bp, "st", &ST) == -1) 1340 ST = DEFSTAT; 1341 if (cgetstr(bp, "lf", &LF) == -1) 1342 LF = _PATH_CONSOLE; 1343 if (cgetstr(bp, "sd", &SD) == -1) 1344 SD = _PATH_DEFSPOOL; 1345 if (cgetnum(bp, "du", &DU) < 0) 1346 DU = DEFUID; 1347 if (cgetstr(bp,"ff", &FF) == -1) 1348 FF = DEFFF; 1349 if (cgetnum(bp, "pw", &PW) < 0) 1350 PW = DEFWIDTH; 1351 sprintf(&width[2], "%ld", PW); 1352 if (cgetnum(bp, "pl", &PL) < 0) 1353 PL = DEFLENGTH;
|