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