1 #ifndef lint 2 static char sccsid[] = "@(#)printjob.c 4.24 (Berkeley) 02/27/85"; 3 #endif 4 5 /* 6 * printjob -- print jobs in the queue. 7 * 8 * NOTE: the lock file is used to pass information to lpq and lprm. 9 * it does not need to be removed because file locks are dynamic. 10 */ 11 12 #include "lp.h" 13 14 #define DORETURN 0 /* absorb fork error */ 15 #define DOABORT 1 /* abort if dofork fails */ 16 17 /* 18 * Error tokens 19 */ 20 #define REPRINT -2 21 #define ERROR -1 22 #define OK 0 23 #define FATALERR 1 24 #define NOACCT 2 25 #define FILTERERR 3 26 #define ACCESS 4 27 28 char title[80]; /* ``pr'' title */ 29 FILE *cfp; /* control file */ 30 int pfd; /* printer file descriptor */ 31 int ofd; /* output filter file descriptor */ 32 int lfd; /* lock file descriptor */ 33 int pid; /* pid of lpd process */ 34 int prchild; /* id of pr process */ 35 int child; /* id of any filters */ 36 int ofilter; /* id of output filter, if any */ 37 int tof; /* true if at top of form */ 38 int remote; /* true if sending files to remote */ 39 dev_t fdev; /* device of file pointed to by symlink */ 40 ino_t fino; /* inode of file pointed to by symlink */ 41 42 char fromhost[32]; /* user's host machine */ 43 char logname[32]; /* user's login name */ 44 char jobname[100]; /* job or file name */ 45 char class[32]; /* classification field */ 46 char width[10] = "-w"; /* page width in characters */ 47 char length[10] = "-l"; /* page length in lines */ 48 char pxwidth[10] = "-x"; /* page width in pixels */ 49 char pxlength[10] = "-y"; /* page length in pixels */ 50 char indent[10] = "-i0"; /* indentation size in characters */ 51 char tmpfile[] = "errsXXXXXX"; /* file name for filter output */ 52 53 printjob() 54 { 55 struct stat stb; 56 register struct queue *q, **qp; 57 struct queue **queue; 58 register int i, nitems; 59 long pidoff; 60 int count = 0; 61 extern int abortpr(); 62 63 init(); /* set up capabilities */ 64 (void) write(1, "", 1); /* ack that daemon is started */ 65 setgid(getegid()); 66 pid = getpid(); /* for use with lprm */ 67 setpgrp(0, pid); 68 signal(SIGHUP, abortpr); 69 signal(SIGINT, abortpr); 70 signal(SIGQUIT, abortpr); 71 signal(SIGTERM, abortpr); 72 73 (void) mktemp(tmpfile); 74 75 /* 76 * uses short form file names 77 */ 78 if (chdir(SD) < 0) { 79 syslog(LOG_ERR, "%s: %m", SD); 80 exit(1); 81 } 82 if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 83 exit(0); /* printing disabled */ 84 lfd = open(LO, O_WRONLY|O_CREAT, 0644); 85 if (lfd < 0) { 86 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 87 exit(1); 88 } 89 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 90 if (errno == EWOULDBLOCK) /* active deamon present */ 91 exit(0); 92 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 93 exit(1); 94 } 95 ftruncate(lfd, 0); 96 /* 97 * write process id for others to know 98 */ 99 sprintf(line, "%u\n", pid); 100 pidoff = i = strlen(line); 101 if (write(lfd, line, i) != i) { 102 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 103 exit(1); 104 } 105 /* 106 * search the spool directory for work and sort by queue order. 107 */ 108 if ((nitems = getq(&queue)) < 0) { 109 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 110 exit(1); 111 } 112 if (nitems == 0) /* no work to do */ 113 exit(0); 114 if (stb.st_mode & 01) { /* reset queue flag */ 115 if (fchmod(lfd, stb.st_mode & 0776) < 0) 116 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 117 } 118 openpr(); /* open printer or remote */ 119 again: 120 /* 121 * we found something to do now do it -- 122 * write the name of the current control file into the lock file 123 * so the spool queue program can tell what we're working on 124 */ 125 for (qp = queue; nitems--; free((char *) q)) { 126 q = *qp++; 127 if (stat(q->q_name, &stb) < 0) 128 continue; 129 restart: 130 (void) lseek(lfd, pidoff, 0); 131 (void) sprintf(line, "%s\n", q->q_name); 132 i = strlen(line); 133 if (write(lfd, line, i) != i) 134 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 135 if (!remote) 136 i = printit(q->q_name); 137 else 138 i = sendit(q->q_name); 139 /* 140 * Check to see if we are supposed to stop printing or 141 * if we are to rebuild the queue. 142 */ 143 if (fstat(lfd, &stb) == 0) { 144 /* stop printing before starting next job? */ 145 if (stb.st_mode & 0100) 146 goto done; 147 /* rebuild queue (after lpc topq) */ 148 if (stb.st_mode & 01) { 149 for (free((char *) q); nitems--; free((char *) q)) 150 q = *qp++; 151 if (fchmod(lfd, stb.st_mode & 0776) < 0) 152 syslog(LOG_WARNING, "%s: %s: %m", 153 printer, LO); 154 break; 155 } 156 } 157 if (i == OK) /* file ok and printed */ 158 count++; 159 else if (i == REPRINT) { /* try reprinting the job */ 160 syslog(LOG_INFO, "restarting %s", printer); 161 if (ofilter > 0) { 162 kill(ofilter, SIGCONT); /* to be sure */ 163 (void) close(ofd); 164 while ((i = wait(0)) > 0 && i != ofilter) 165 ; 166 ofilter = 0; 167 } 168 (void) close(pfd); /* close printer */ 169 if (ftruncate(lfd, pidoff) < 0) 170 syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 171 openpr(); /* try to reopen printer */ 172 goto restart; 173 } 174 } 175 free((char *) queue); 176 /* 177 * search the spool directory for more work. 178 */ 179 if ((nitems = getq(&queue)) < 0) { 180 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 181 exit(1); 182 } 183 if (nitems == 0) { /* no more work to do */ 184 done: 185 if (count > 0) { /* Files actually printed */ 186 if (!SF && !tof) 187 (void) write(ofd, FF, strlen(FF)); 188 if (TR != NULL) /* output trailer */ 189 (void) write(ofd, TR, strlen(TR)); 190 } 191 (void) unlink(tmpfile); 192 exit(0); 193 } 194 goto again; 195 } 196 197 char fonts[4][50]; /* fonts for troff */ 198 199 char ifonts[4][18] = { 200 "/usr/lib/vfont/R", 201 "/usr/lib/vfont/I", 202 "/usr/lib/vfont/B", 203 "/usr/lib/vfont/S" 204 }; 205 206 /* 207 * The remaining part is the reading of the control file (cf) 208 * and performing the various actions. 209 */ 210 printit(file) 211 char *file; 212 { 213 register int i; 214 char *cp; 215 int bombed = OK; 216 217 /* 218 * open control file; ignore if no longer there. 219 */ 220 if ((cfp = fopen(file, "r")) == NULL) { 221 syslog(LOG_INFO, "%s: %s: %m", printer, file); 222 return(OK); 223 } 224 /* 225 * Reset troff fonts. 226 */ 227 for (i = 0; i < 4; i++) 228 strcpy(fonts[i], ifonts[i]); 229 strcpy(width+2, "0"); 230 strcpy(indent+2, "0"); 231 232 /* 233 * read the control file for work to do 234 * 235 * file format -- first character in the line is a command 236 * rest of the line is the argument. 237 * valid commands are: 238 * 239 * S -- "stat info" for symbolic link protection 240 * J -- "job name" on banner page 241 * C -- "class name" on banner page 242 * L -- "literal" user's name to print on banner 243 * T -- "title" for pr 244 * H -- "host name" of machine where lpr was done 245 * P -- "person" user's login name 246 * I -- "indent" amount to indent output 247 * f -- "file name" name of text file to print 248 * l -- "file name" text file with control chars 249 * p -- "file name" text file to print with pr(1) 250 * t -- "file name" troff(1) file to print 251 * n -- "file name" ditroff(1) file to print 252 * d -- "file name" dvi file to print 253 * g -- "file name" plot(1G) file to print 254 * v -- "file name" plain raster file to print 255 * c -- "file name" cifplot file to print 256 * 1 -- "R font file" for troff 257 * 2 -- "I font file" for troff 258 * 3 -- "B font file" for troff 259 * 4 -- "S font file" for troff 260 * N -- "name" of file (used by lpq) 261 * U -- "unlink" name of file to remove 262 * (after we print it. (Pass 2 only)). 263 * M -- "mail" to user when done printing 264 * 265 * getline reads a line and expands tabs to blanks 266 */ 267 268 /* pass 1 */ 269 270 while (getline(cfp)) 271 switch (line[0]) { 272 case 'H': 273 strcpy(fromhost, line+1); 274 if (class[0] == '\0') 275 strncpy(class, line+1, sizeof(class)-1); 276 continue; 277 278 case 'P': 279 strncpy(logname, line+1, sizeof(logname)-1); 280 if (RS) { /* restricted */ 281 if (getpwnam(logname) == (struct passwd *)0) { 282 bombed = NOACCT; 283 sendmail(line+1, bombed); 284 goto pass2; 285 } 286 } 287 continue; 288 289 case 'S': 290 cp = line+1; 291 i = 0; 292 while (*cp >= '0' && *cp <= '9') 293 i = i * 10 + (*cp++ - '0'); 294 fdev = i; 295 cp++; 296 i = 0; 297 while (*cp >= '0' && *cp <= '9') 298 i = i * 10 + (*cp++ - '0'); 299 fino = i; 300 continue; 301 302 case 'J': 303 if (line[1] != '\0') 304 strncpy(jobname, line+1, sizeof(jobname)-1); 305 else 306 strcpy(jobname, " "); 307 continue; 308 309 case 'C': 310 if (line[1] != '\0') 311 strncpy(class, line+1, sizeof(class)-1); 312 else if (class[0] == '\0') 313 gethostname(class, sizeof(class)); 314 continue; 315 316 case 'T': /* header title for pr */ 317 strncpy(title, line+1, sizeof(title)-1); 318 continue; 319 320 case 'L': /* identification line */ 321 if (!SH && !HL) 322 banner(line+1, jobname); 323 continue; 324 325 case '1': /* troff fonts */ 326 case '2': 327 case '3': 328 case '4': 329 if (line[1] != '\0') 330 strcpy(fonts[line[0]-'1'], line+1); 331 continue; 332 333 case 'W': /* page width */ 334 strncpy(width+2, line+1, sizeof(width)-3); 335 continue; 336 337 case 'I': /* indent amount */ 338 strncpy(indent+2, line+1, sizeof(indent)-3); 339 continue; 340 341 default: /* some file to print */ 342 switch (i = print(line[0], line+1)) { 343 case ERROR: 344 if (bombed == OK) 345 bombed = FATALERR; 346 break; 347 case REPRINT: 348 (void) fclose(cfp); 349 return(REPRINT); 350 case FILTERERR: 351 case ACCESS: 352 bombed = i; 353 sendmail(logname, bombed); 354 } 355 title[0] = '\0'; 356 continue; 357 358 case 'N': 359 case 'U': 360 case 'M': 361 continue; 362 } 363 364 /* pass 2 */ 365 366 pass2: 367 fseek(cfp, 0L, 0); 368 while (getline(cfp)) 369 switch (line[0]) { 370 case 'L': /* identification line */ 371 if (!SH && HL) 372 banner(line+1, jobname); 373 continue; 374 375 case 'M': 376 if (bombed < NOACCT) /* already sent if >= NOACCT */ 377 sendmail(line+1, bombed); 378 continue; 379 380 case 'U': 381 (void) unlink(line+1); 382 } 383 /* 384 * clean-up in case another control file exists 385 */ 386 (void) fclose(cfp); 387 (void) unlink(file); 388 return(bombed == OK ? OK : ERROR); 389 } 390 391 /* 392 * Print a file. 393 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 394 * Return -1 if a non-recoverable error occured, 395 * 2 if the filter detected some errors (but printed the job anyway), 396 * 1 if we should try to reprint this job and 397 * 0 if all is well. 398 * Note: all filters take stdin as the file, stdout as the printer, 399 * stderr as the log file, and must not ignore SIGINT. 400 */ 401 print(format, file) 402 int format; 403 char *file; 404 { 405 register int n; 406 register char *prog; 407 int fi, fo; 408 char *av[15], buf[BUFSIZ]; 409 int pid, p[2], stopped = 0; 410 union wait status; 411 struct stat stb; 412 413 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 414 return(ERROR); 415 /* 416 * Check to see if data file is a symbolic link. If so, it should 417 * still point to the same file or someone is trying to print 418 * something he shouldn't. 419 */ 420 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 421 (stb.st_dev != fdev || stb.st_ino != fino)) 422 return(ACCESS); 423 if (!SF && !tof) { /* start on a fresh page */ 424 (void) write(ofd, FF, strlen(FF)); 425 tof = 1; 426 } 427 if (IF == NULL && (format == 'f' || format == 'l')) { 428 tof = 0; 429 while ((n = read(fi, buf, BUFSIZ)) > 0) 430 if (write(ofd, buf, n) != n) { 431 (void) close(fi); 432 return(REPRINT); 433 } 434 (void) close(fi); 435 return(OK); 436 } 437 switch (format) { 438 case 'p': /* print file using 'pr' */ 439 if (IF == NULL) { /* use output filter */ 440 prog = PR; 441 av[0] = "pr"; 442 av[1] = width; 443 av[2] = length; 444 av[3] = "-h"; 445 av[4] = *title ? title : " "; 446 av[5] = 0; 447 fo = ofd; 448 goto start; 449 } 450 pipe(p); 451 if ((prchild = dofork(DORETURN)) == 0) { /* child */ 452 dup2(fi, 0); /* file is stdin */ 453 dup2(p[1], 1); /* pipe is stdout */ 454 for (n = 3; n < NOFILE; n++) 455 (void) close(n); 456 execl(PR, "pr", width, length, "-h", *title ? title : " ", 0); 457 syslog(LOG_ERR, "cannot execl %s", PR); 458 exit(2); 459 } 460 (void) close(p[1]); /* close output side */ 461 (void) close(fi); 462 if (prchild < 0) { 463 prchild = 0; 464 (void) close(p[0]); 465 return(ERROR); 466 } 467 fi = p[0]; /* use pipe for input */ 468 case 'f': /* print plain text file */ 469 prog = IF; 470 av[1] = width; 471 av[2] = length; 472 av[3] = indent; 473 n = 4; 474 break; 475 case 'l': /* like 'f' but pass control characters */ 476 prog = IF; 477 av[1] = "-c"; 478 av[2] = width; 479 av[3] = length; 480 av[4] = indent; 481 n = 5; 482 break; 483 case 'r': /* print a fortran text file */ 484 prog = RF; 485 av[1] = width; 486 av[2] = length; 487 n = 3; 488 break; 489 case 't': /* print troff output */ 490 case 'n': /* print ditroff output */ 491 case 'd': /* print tex output */ 492 (void) unlink(".railmag"); 493 if ((fo = creat(".railmag", FILMOD)) < 0) { 494 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 495 (void) unlink(".railmag"); 496 } else { 497 for (n = 0; n < 4; n++) { 498 if (fonts[n][0] != '/') 499 (void) write(fo, "/usr/lib/vfont/", 15); 500 (void) write(fo, fonts[n], strlen(fonts[n])); 501 (void) write(fo, "\n", 1); 502 } 503 (void) close(fo); 504 } 505 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 506 av[1] = pxwidth; 507 av[2] = pxlength; 508 n = 3; 509 break; 510 case 'c': /* print cifplot output */ 511 prog = CF; 512 av[1] = pxwidth; 513 av[2] = pxlength; 514 n = 3; 515 break; 516 case 'g': /* print plot(1G) output */ 517 prog = GF; 518 av[1] = pxwidth; 519 av[2] = pxlength; 520 n = 3; 521 break; 522 case 'v': /* print raster output */ 523 prog = VF; 524 av[1] = pxwidth; 525 av[2] = pxlength; 526 n = 3; 527 break; 528 default: 529 (void) close(fi); 530 syslog(LOG_ERR, "%s: illegal format character '%c'", 531 printer, format); 532 return(ERROR); 533 } 534 if ((av[0] = rindex(prog, '/')) != NULL) 535 av[0]++; 536 else 537 av[0] = prog; 538 av[n++] = "-n"; 539 av[n++] = logname; 540 av[n++] = "-h"; 541 av[n++] = fromhost; 542 av[n++] = AF; 543 av[n] = 0; 544 fo = pfd; 545 if (ofilter > 0) { /* stop output filter */ 546 write(ofd, "\031\1", 2); 547 while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 548 ; 549 if (status.w_stopval != WSTOPPED) { 550 (void) close(fi); 551 syslog(LOG_WARNING, "%s: output filter died (%d)", 552 printer, status.w_retcode); 553 return(REPRINT); 554 } 555 stopped++; 556 } 557 start: 558 if ((child = dofork(DORETURN)) == 0) { /* child */ 559 dup2(fi, 0); 560 dup2(fo, 1); 561 n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 562 if (n >= 0) 563 dup2(n, 2); 564 for (n = 3; n < NOFILE; n++) 565 (void) close(n); 566 execv(prog, av); 567 syslog(LOG_ERR, "cannot execv %s", prog); 568 exit(2); 569 } 570 (void) close(fi); 571 if (child < 0) 572 status.w_retcode = 100; 573 else 574 while ((pid = wait(&status)) > 0 && pid != child) 575 ; 576 child = 0; 577 prchild = 0; 578 if (stopped) { /* restart output filter */ 579 if (kill(ofilter, SIGCONT) < 0) { 580 syslog(LOG_ERR, "cannot restart output filter"); 581 exit(1); 582 } 583 } 584 tof = 0; 585 if (!WIFEXITED(status)) { 586 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 587 printer, format, status.w_termsig); 588 return(ERROR); 589 } 590 switch (status.w_retcode) { 591 case 0: 592 tof = 1; 593 return(OK); 594 case 1: 595 return(REPRINT); 596 default: 597 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 598 printer, format, status.w_retcode); 599 case 2: 600 return(ERROR); 601 } 602 } 603 604 /* 605 * Send the daemon control file (cf) and any data files. 606 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 607 * 0 if all is well. 608 */ 609 sendit(file) 610 char *file; 611 { 612 register int i, err = OK; 613 char *cp, last[BUFSIZ]; 614 615 /* 616 * open control file 617 */ 618 if ((cfp = fopen(file, "r")) == NULL) 619 return(OK); 620 /* 621 * read the control file for work to do 622 * 623 * file format -- first character in the line is a command 624 * rest of the line is the argument. 625 * commands of interest are: 626 * 627 * a-z -- "file name" name of file to print 628 * U -- "unlink" name of file to remove 629 * (after we print it. (Pass 2 only)). 630 */ 631 632 /* 633 * pass 1 634 */ 635 while (getline(cfp)) { 636 again: 637 if (line[0] == 'S') { 638 cp = line+1; 639 i = 0; 640 while (*cp >= '0' && *cp <= '9') 641 i = i * 10 + (*cp++ - '0'); 642 fdev = i; 643 cp++; 644 i = 0; 645 while (*cp >= '0' && *cp <= '9') 646 i = i * 10 + (*cp++ - '0'); 647 fino = i; 648 continue; 649 } 650 if (line[0] >= 'a' && line[0] <= 'z') { 651 strcpy(last, line); 652 while (i = getline(cfp)) 653 if (strcmp(last, line)) 654 break; 655 switch (sendfile('\3', last+1)) { 656 case OK: 657 if (i) 658 goto again; 659 break; 660 case REPRINT: 661 (void) fclose(cfp); 662 return(REPRINT); 663 case ACCESS: 664 sendmail(logname, ACCESS); 665 case ERROR: 666 err = ERROR; 667 } 668 break; 669 } 670 } 671 if (err == OK && sendfile('\2', file) > 0) { 672 (void) fclose(cfp); 673 return(REPRINT); 674 } 675 /* 676 * pass 2 677 */ 678 fseek(cfp, 0L, 0); 679 while (getline(cfp)) 680 if (line[0] == 'U') 681 (void) unlink(line+1); 682 /* 683 * clean-up in case another control file exists 684 */ 685 (void) fclose(cfp); 686 (void) unlink(file); 687 return(err); 688 } 689 690 /* 691 * Send a data file to the remote machine and spool it. 692 * Return positive if we should try resending. 693 */ 694 sendfile(type, file) 695 char type, *file; 696 { 697 register int f, i, amt; 698 struct stat stb; 699 char buf[BUFSIZ]; 700 int sizerr, resp; 701 702 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 703 return(ERROR); 704 /* 705 * Check to see if data file is a symbolic link. If so, it should 706 * still point to the same file or someone is trying to print something 707 * he shouldn't. 708 */ 709 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 710 (stb.st_dev != fdev || stb.st_ino != fino)) 711 return(ACCESS); 712 (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 713 amt = strlen(buf); 714 for (i = 0; ; i++) { 715 if (write(pfd, buf, amt) != amt || 716 (resp = response()) < 0 || resp == '\1') { 717 (void) close(f); 718 return(REPRINT); 719 } else if (resp == '\0') 720 break; 721 if (i == 0) 722 status("no space on remote; waiting for queue to drain"); 723 if (i == 10) 724 syslog(LOG_SALERT, "%s: can't send to %s; queue full", 725 printer, RM); 726 sleep(5 * 60); 727 } 728 if (i) 729 status("sending to %s", RM); 730 sizerr = 0; 731 for (i = 0; i < stb.st_size; i += BUFSIZ) { 732 amt = BUFSIZ; 733 if (i + amt > stb.st_size) 734 amt = stb.st_size - i; 735 if (sizerr == 0 && read(f, buf, amt) != amt) 736 sizerr = 1; 737 if (write(pfd, buf, amt) != amt) { 738 (void) close(f); 739 return(REPRINT); 740 } 741 } 742 (void) close(f); 743 if (sizerr) { 744 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 745 /* tell recvjob to ignore this file */ 746 (void) write(pfd, "\1", 1); 747 return(ERROR); 748 } 749 if (write(pfd, "", 1) != 1 || response()) 750 return(REPRINT); 751 return(OK); 752 } 753 754 /* 755 * Check to make sure there have been no errors and that both programs 756 * are in sync with eachother. 757 * Return non-zero if the connection was lost. 758 */ 759 response() 760 { 761 char resp; 762 763 if (read(pfd, &resp, 1) != 1) { 764 syslog(LOG_INFO, "%s: lost connection", printer); 765 return(-1); 766 } 767 return(resp); 768 } 769 770 /* 771 * Banner printing stuff 772 */ 773 banner(name1, name2) 774 char *name1, *name2; 775 { 776 time_t tvec; 777 extern char *ctime(); 778 779 time(&tvec); 780 if (!SF && !tof) 781 (void) write(ofd, FF, strlen(FF)); 782 if (SB) { /* short banner only */ 783 if (class[0]) { 784 (void) write(ofd, class, strlen(class)); 785 (void) write(ofd, ":", 1); 786 } 787 (void) write(ofd, name1, strlen(name1)); 788 (void) write(ofd, " Job: ", 7); 789 (void) write(ofd, name2, strlen(name2)); 790 (void) write(ofd, " Date: ", 8); 791 (void) write(ofd, ctime(&tvec), 24); 792 (void) write(ofd, "\n", 1); 793 } else { /* normal banner */ 794 (void) write(ofd, "\n\n\n", 3); 795 scan_out(ofd, name1, '\0'); 796 (void) write(ofd, "\n\n", 2); 797 scan_out(ofd, name2, '\0'); 798 if (class[0]) { 799 (void) write(ofd,"\n\n\n",3); 800 scan_out(ofd, class, '\0'); 801 } 802 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 803 (void) write(ofd, name2, strlen(name2)); 804 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 805 (void) write(ofd, ctime(&tvec), 24); 806 (void) write(ofd, "\n", 1); 807 } 808 if (!SF) 809 (void) write(ofd, FF, strlen(FF)); 810 tof = 1; 811 } 812 813 char * 814 scnline(key, p, c) 815 register char key, *p; 816 char c; 817 { 818 register scnwidth; 819 820 for (scnwidth = WIDTH; --scnwidth;) { 821 key <<= 1; 822 *p++ = key & 0200 ? c : BACKGND; 823 } 824 return (p); 825 } 826 827 #define TRC(q) (((q)-' ')&0177) 828 829 scan_out(scfd, scsp, dlm) 830 int scfd; 831 char *scsp, dlm; 832 { 833 register char *strp; 834 register nchrs, j; 835 char outbuf[LINELEN+1], *sp, c, cc; 836 int d, scnhgt; 837 extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 838 839 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 840 strp = &outbuf[0]; 841 sp = scsp; 842 for (nchrs = 0; ; ) { 843 d = dropit(c = TRC(cc = *sp++)); 844 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 845 for (j = WIDTH; --j;) 846 *strp++ = BACKGND; 847 else 848 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 849 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 850 break; 851 *strp++ = BACKGND; 852 *strp++ = BACKGND; 853 } 854 while (*--strp == BACKGND && strp >= outbuf) 855 ; 856 strp++; 857 *strp++ = '\n'; 858 (void) write(scfd, outbuf, strp-outbuf); 859 } 860 } 861 862 dropit(c) 863 char c; 864 { 865 switch(c) { 866 867 case TRC('_'): 868 case TRC(';'): 869 case TRC(','): 870 case TRC('g'): 871 case TRC('j'): 872 case TRC('p'): 873 case TRC('q'): 874 case TRC('y'): 875 return (DROP); 876 877 default: 878 return (0); 879 } 880 } 881 882 /* 883 * sendmail --- 884 * tell people about job completion 885 */ 886 sendmail(user, bombed) 887 char *user; 888 int bombed; 889 { 890 register int i; 891 int p[2], s; 892 register char *cp; 893 char buf[100]; 894 struct stat stb; 895 FILE *fp; 896 897 pipe(p); 898 if ((s = dofork(DORETURN)) == 0) { /* child */ 899 dup2(p[0], 0); 900 for (i = 3; i < NOFILE; i++) 901 (void) close(i); 902 if ((cp = rindex(MAIL, '/')) != NULL) 903 cp++; 904 else 905 cp = MAIL; 906 sprintf(buf, "%s@%s", user, fromhost); 907 execl(MAIL, cp, buf, 0); 908 exit(0); 909 } else if (s > 0) { /* parent */ 910 dup2(p[1], 1); 911 printf("To: %s@%s\n", user, fromhost); 912 printf("Subject: printer job\n\n"); 913 printf("Your printer job "); 914 if (*jobname) 915 printf("(%s) ", jobname); 916 switch (bombed) { 917 case OK: 918 printf("\ncompleted successfully\n"); 919 break; 920 default: 921 case FATALERR: 922 printf("\ncould not be printed\n"); 923 break; 924 case NOACCT: 925 printf("\ncould not be printed without an account on %s\n", host); 926 break; 927 case FILTERERR: 928 if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 || 929 (fp = fopen(tmpfile, "r")) == NULL) { 930 printf("\nwas printed but had some errors\n"); 931 break; 932 } 933 printf("\nwas printed but had the following errors:\n"); 934 while ((i = getc(fp)) != EOF) 935 putchar(i); 936 (void) fclose(fp); 937 break; 938 case ACCESS: 939 printf("\nwas not printed because it was not linked to the original file\n"); 940 } 941 fflush(stdout); 942 (void) close(1); 943 } 944 (void) close(p[0]); 945 (void) close(p[1]); 946 wait(&s); 947 } 948 949 /* 950 * dofork - fork with retries on failure 951 */ 952 dofork(action) 953 int action; 954 { 955 register int i, pid; 956 957 for (i = 0; i < 20; i++) { 958 if ((pid = fork()) < 0) { 959 sleep((unsigned)(i*i)); 960 continue; 961 } 962 /* 963 * Child should run as daemon instead of root 964 */ 965 if (pid == 0) 966 setuid(DU); 967 return(pid); 968 } 969 syslog(LOG_ERR, "can't fork"); 970 971 switch (action) { 972 case DORETURN: 973 return (-1); 974 default: 975 syslog(LOG_ERR, "bad action (%d) to dofork", action); 976 /*FALL THRU*/ 977 case DOABORT: 978 exit(1); 979 } 980 /*NOTREACHED*/ 981 } 982 983 /* 984 * Kill child processes to abort current job. 985 */ 986 abortpr() 987 { 988 (void) unlink(tmpfile); 989 kill(0, SIGINT); 990 if (ofilter > 0) 991 kill(ofilter, SIGCONT); 992 while (wait(0) > 0) 993 ; 994 exit(0); 995 } 996 997 init() 998 { 999 int status; 1000 1001 if ((status = pgetent(line, printer)) < 0) 1002 fatal("can't open printer description file"); 1003 else if (status == 0) 1004 fatal("unknown printer"); 1005 if ((LP = pgetstr("lp", &bp)) == NULL) 1006 LP = DEFDEVLP; 1007 if ((RP = pgetstr("rp", &bp)) == NULL) 1008 RP = DEFLP; 1009 if ((LO = pgetstr("lo", &bp)) == NULL) 1010 LO = DEFLOCK; 1011 if ((ST = pgetstr("st", &bp)) == NULL) 1012 ST = DEFSTAT; 1013 if ((LF = pgetstr("lf", &bp)) == NULL) 1014 LF = DEFLOGF; 1015 if ((SD = pgetstr("sd", &bp)) == NULL) 1016 SD = DEFSPOOL; 1017 if ((DU = pgetnum("du")) < 0) 1018 DU = DEFUID; 1019 if ((FF = pgetstr("ff", &bp)) == NULL) 1020 FF = DEFFF; 1021 if ((PW = pgetnum("pw")) < 0) 1022 PW = DEFWIDTH; 1023 sprintf(&width[2], "%d", PW); 1024 if ((PL = pgetnum("pl")) < 0) 1025 PL = DEFLENGTH; 1026 sprintf(&length[2], "%d", PL); 1027 if ((PX = pgetnum("px")) < 0) 1028 PX = 0; 1029 sprintf(&pxwidth[2], "%d", PX); 1030 if ((PY = pgetnum("py")) < 0) 1031 PY = 0; 1032 sprintf(&pxlength[2], "%d", PY); 1033 RM = pgetstr("rm", &bp); 1034 AF = pgetstr("af", &bp); 1035 OF = pgetstr("of", &bp); 1036 IF = pgetstr("if", &bp); 1037 RF = pgetstr("rf", &bp); 1038 TF = pgetstr("tf", &bp); 1039 NF = pgetstr("nf", &bp); 1040 DF = pgetstr("df", &bp); 1041 GF = pgetstr("gf", &bp); 1042 VF = pgetstr("vf", &bp); 1043 CF = pgetstr("cf", &bp); 1044 TR = pgetstr("tr", &bp); 1045 RS = pgetflag("rs"); 1046 SF = pgetflag("sf"); 1047 SH = pgetflag("sh"); 1048 SB = pgetflag("sb"); 1049 HL = pgetflag("hl"); 1050 RW = pgetflag("rw"); 1051 BR = pgetnum("br"); 1052 if ((FC = pgetnum("fc")) < 0) 1053 FC = 0; 1054 if ((FS = pgetnum("fs")) < 0) 1055 FS = 0; 1056 if ((XC = pgetnum("xc")) < 0) 1057 XC = 0; 1058 if ((XS = pgetnum("xs")) < 0) 1059 XS = 0; 1060 tof = !pgetflag("fo"); 1061 } 1062 1063 /* 1064 * Acquire line printer or remote connection. 1065 */ 1066 openpr() 1067 { 1068 register int i, n; 1069 int resp; 1070 1071 if (*LP) { 1072 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1073 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1074 if (pfd >= 0) 1075 break; 1076 if (errno == ENOENT) { 1077 syslog(LOG_ERR, "%s: %m", LP); 1078 exit(1); 1079 } 1080 if (i == 1) 1081 status("waiting for %s to become ready (offline ?)", printer); 1082 sleep(i); 1083 } 1084 if (isatty(pfd)) 1085 setty(); 1086 status("%s is ready and printing", printer); 1087 } else if (RM != NULL) { 1088 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1089 resp = -1; 1090 pfd = getport(RM); 1091 if (pfd >= 0) { 1092 (void) sprintf(line, "\2%s\n", RP); 1093 n = strlen(line); 1094 if (write(pfd, line, n) == n && 1095 (resp = response()) == '\0') 1096 break; 1097 (void) close(pfd); 1098 } 1099 if (i == 1) { 1100 if (resp < 0) 1101 status("waiting for %s to come up", RM); 1102 else { 1103 status("waiting for queue to be enabled on %s", RM); 1104 i = 256; 1105 } 1106 } 1107 sleep(i); 1108 } 1109 status("sending to %s", RM); 1110 remote = 1; 1111 } else { 1112 syslog(LOG_ERR, "%s: no line printer device or host name", 1113 printer); 1114 exit(1); 1115 } 1116 /* 1117 * Start up an output filter, if needed. 1118 */ 1119 if (OF) { 1120 int p[2]; 1121 char *cp; 1122 1123 pipe(p); 1124 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1125 dup2(p[0], 0); /* pipe is std in */ 1126 dup2(pfd, 1); /* printer is std out */ 1127 for (i = 3; i < NOFILE; i++) 1128 (void) close(i); 1129 if ((cp = rindex(OF, '/')) == NULL) 1130 cp = OF; 1131 else 1132 cp++; 1133 execl(OF, cp, width, length, 0); 1134 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1135 exit(1); 1136 } 1137 (void) close(p[0]); /* close input side */ 1138 ofd = p[1]; /* use pipe for output */ 1139 } else { 1140 ofd = pfd; 1141 ofilter = 0; 1142 } 1143 } 1144 1145 struct bauds { 1146 int baud; 1147 int speed; 1148 } bauds[] = { 1149 50, B50, 1150 75, B75, 1151 110, B110, 1152 134, B134, 1153 150, B150, 1154 200, B200, 1155 300, B300, 1156 600, B600, 1157 1200, B1200, 1158 1800, B1800, 1159 2400, B2400, 1160 4800, B4800, 1161 9600, B9600, 1162 19200, EXTA, 1163 38400, EXTB, 1164 0, 0 1165 }; 1166 1167 /* 1168 * setup tty lines. 1169 */ 1170 setty() 1171 { 1172 struct sgttyb ttybuf; 1173 register struct bauds *bp; 1174 1175 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1176 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1177 exit(1); 1178 } 1179 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1180 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1181 exit(1); 1182 } 1183 if (BR > 0) { 1184 for (bp = bauds; bp->baud; bp++) 1185 if (BR == bp->baud) 1186 break; 1187 if (!bp->baud) { 1188 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1189 exit(1); 1190 } 1191 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1192 } 1193 ttybuf.sg_flags &= ~FC; 1194 ttybuf.sg_flags |= FS; 1195 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1196 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1197 exit(1); 1198 } 1199 if (XC || XS) { 1200 int ldisc = NTTYDISC; 1201 1202 if (ioctl(pfd, TIOCSETD, &ldisc) < 0) { 1203 syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer); 1204 exit(1); 1205 } 1206 } 1207 if (XC) { 1208 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1209 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1210 exit(1); 1211 } 1212 } 1213 if (XS) { 1214 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1215 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1216 exit(1); 1217 } 1218 } 1219 } 1220 1221 /*VARARGS1*/ 1222 status(msg, a1, a2, a3) 1223 char *msg; 1224 { 1225 register int fd; 1226 char buf[BUFSIZ]; 1227 1228 umask(0); 1229 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1230 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1231 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1232 exit(1); 1233 } 1234 ftruncate(fd, 0); 1235 sprintf(buf, msg, a1, a2, a3); 1236 strcat(buf, "\n"); 1237 (void) write(fd, buf, strlen(buf)); 1238 (void) close(fd); 1239 } 1240