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