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