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.12 (Berkeley) 06/01/90"; 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 extern int 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, 15); 515 (void) write(fo, fonts[n], strlen(fonts[n])); 516 (void) write(fo, "\n", 1); 517 } 518 (void) close(fo); 519 } 520 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 521 av[1] = pxwidth; 522 av[2] = pxlength; 523 n = 3; 524 break; 525 case 'c': /* print cifplot output */ 526 prog = CF; 527 av[1] = pxwidth; 528 av[2] = pxlength; 529 n = 3; 530 break; 531 case 'g': /* print plot(1G) output */ 532 prog = GF; 533 av[1] = pxwidth; 534 av[2] = pxlength; 535 n = 3; 536 break; 537 case 'v': /* print raster output */ 538 prog = VF; 539 av[1] = pxwidth; 540 av[2] = pxlength; 541 n = 3; 542 break; 543 default: 544 (void) close(fi); 545 syslog(LOG_ERR, "%s: illegal format character '%c'", 546 printer, format); 547 return(ERROR); 548 } 549 if ((av[0] = rindex(prog, '/')) != NULL) 550 av[0]++; 551 else 552 av[0] = prog; 553 av[n++] = "-n"; 554 av[n++] = logname; 555 av[n++] = "-h"; 556 av[n++] = fromhost; 557 av[n++] = AF; 558 av[n] = 0; 559 fo = pfd; 560 if (ofilter > 0) { /* stop output filter */ 561 write(ofd, "\031\1", 2); 562 while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter) 563 ; 564 if (status.w_stopval != WSTOPPED) { 565 (void) close(fi); 566 syslog(LOG_WARNING, "%s: output filter died (%d)", 567 printer, status.w_retcode); 568 return(REPRINT); 569 } 570 stopped++; 571 } 572 start: 573 if ((child = dofork(DORETURN)) == 0) { /* child */ 574 dup2(fi, 0); 575 dup2(fo, 1); 576 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 577 if (n >= 0) 578 dup2(n, 2); 579 for (n = 3; n < NOFILE; n++) 580 (void) close(n); 581 execv(prog, av); 582 syslog(LOG_ERR, "cannot execv %s", prog); 583 exit(2); 584 } 585 (void) close(fi); 586 if (child < 0) 587 status.w_retcode = 100; 588 else 589 while ((pid = wait(&status)) > 0 && pid != child) 590 ; 591 child = 0; 592 prchild = 0; 593 if (stopped) { /* restart output filter */ 594 if (kill(ofilter, SIGCONT) < 0) { 595 syslog(LOG_ERR, "cannot restart output filter"); 596 exit(1); 597 } 598 } 599 tof = 0; 600 601 /* Copy filter output to "lf" logfile */ 602 if (fp = fopen(tempfile, "r")) { 603 char tbuf[512]; 604 605 while (fgets(buf, sizeof(buf), fp)) 606 fputs(buf, stderr); 607 close(fp); 608 } 609 610 if (!WIFEXITED(status)) { 611 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 612 printer, format, status.w_termsig); 613 return(ERROR); 614 } 615 switch (status.w_retcode) { 616 case 0: 617 tof = 1; 618 return(OK); 619 case 1: 620 return(REPRINT); 621 default: 622 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 623 printer, format, status.w_retcode); 624 case 2: 625 return(ERROR); 626 } 627 } 628 629 /* 630 * Send the daemon control file (cf) and any data files. 631 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 632 * 0 if all is well. 633 */ 634 sendit(file) 635 char *file; 636 { 637 register int i, err = OK; 638 char *cp, last[BUFSIZ]; 639 640 /* 641 * open control file 642 */ 643 if ((cfp = fopen(file, "r")) == NULL) 644 return(OK); 645 /* 646 * read the control file for work to do 647 * 648 * file format -- first character in the line is a command 649 * rest of the line is the argument. 650 * commands of interest are: 651 * 652 * a-z -- "file name" name of file to print 653 * U -- "unlink" name of file to remove 654 * (after we print it. (Pass 2 only)). 655 */ 656 657 /* 658 * pass 1 659 */ 660 while (getline(cfp)) { 661 again: 662 if (line[0] == 'S') { 663 cp = line+1; 664 i = 0; 665 while (*cp >= '0' && *cp <= '9') 666 i = i * 10 + (*cp++ - '0'); 667 fdev = i; 668 cp++; 669 i = 0; 670 while (*cp >= '0' && *cp <= '9') 671 i = i * 10 + (*cp++ - '0'); 672 fino = i; 673 continue; 674 } 675 if (line[0] >= 'a' && line[0] <= 'z') { 676 strcpy(last, line); 677 while (i = getline(cfp)) 678 if (strcmp(last, line)) 679 break; 680 switch (sendfile('\3', last+1)) { 681 case OK: 682 if (i) 683 goto again; 684 break; 685 case REPRINT: 686 (void) fclose(cfp); 687 return(REPRINT); 688 case ACCESS: 689 sendmail(logname, ACCESS); 690 case ERROR: 691 err = ERROR; 692 } 693 break; 694 } 695 } 696 if (err == OK && sendfile('\2', file) > 0) { 697 (void) fclose(cfp); 698 return(REPRINT); 699 } 700 /* 701 * pass 2 702 */ 703 fseek(cfp, 0L, 0); 704 while (getline(cfp)) 705 if (line[0] == 'U') 706 (void) unlink(line+1); 707 /* 708 * clean-up in case another control file exists 709 */ 710 (void) fclose(cfp); 711 (void) unlink(file); 712 return(err); 713 } 714 715 /* 716 * Send a data file to the remote machine and spool it. 717 * Return positive if we should try resending. 718 */ 719 sendfile(type, file) 720 char type, *file; 721 { 722 register int f, i, amt; 723 struct stat stb; 724 char buf[BUFSIZ]; 725 int sizerr, resp; 726 727 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 728 return(ERROR); 729 /* 730 * Check to see if data file is a symbolic link. If so, it should 731 * still point to the same file or someone is trying to print something 732 * he shouldn't. 733 */ 734 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 735 (stb.st_dev != fdev || stb.st_ino != fino)) 736 return(ACCESS); 737 (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file); 738 amt = strlen(buf); 739 for (i = 0; ; i++) { 740 if (write(pfd, buf, amt) != amt || 741 (resp = response()) < 0 || resp == '\1') { 742 (void) close(f); 743 return(REPRINT); 744 } else if (resp == '\0') 745 break; 746 if (i == 0) 747 status("no space on remote; waiting for queue to drain"); 748 if (i == 10) 749 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 750 printer, RM); 751 sleep(5 * 60); 752 } 753 if (i) 754 status("sending to %s", RM); 755 sizerr = 0; 756 for (i = 0; i < stb.st_size; i += BUFSIZ) { 757 amt = BUFSIZ; 758 if (i + amt > stb.st_size) 759 amt = stb.st_size - i; 760 if (sizerr == 0 && read(f, buf, amt) != amt) 761 sizerr = 1; 762 if (write(pfd, buf, amt) != amt) { 763 (void) close(f); 764 return(REPRINT); 765 } 766 } 767 (void) close(f); 768 if (sizerr) { 769 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 770 /* tell recvjob to ignore this file */ 771 (void) write(pfd, "\1", 1); 772 return(ERROR); 773 } 774 if (write(pfd, "", 1) != 1 || response()) 775 return(REPRINT); 776 return(OK); 777 } 778 779 /* 780 * Check to make sure there have been no errors and that both programs 781 * are in sync with eachother. 782 * Return non-zero if the connection was lost. 783 */ 784 response() 785 { 786 char resp; 787 788 if (read(pfd, &resp, 1) != 1) { 789 syslog(LOG_INFO, "%s: lost connection", printer); 790 return(-1); 791 } 792 return(resp); 793 } 794 795 /* 796 * Banner printing stuff 797 */ 798 banner(name1, name2) 799 char *name1, *name2; 800 { 801 time_t tvec; 802 extern char *ctime(); 803 804 time(&tvec); 805 if (!SF && !tof) 806 (void) write(ofd, FF, strlen(FF)); 807 if (SB) { /* short banner only */ 808 if (class[0]) { 809 (void) write(ofd, class, strlen(class)); 810 (void) write(ofd, ":", 1); 811 } 812 (void) write(ofd, name1, strlen(name1)); 813 (void) write(ofd, " Job: ", 7); 814 (void) write(ofd, name2, strlen(name2)); 815 (void) write(ofd, " Date: ", 8); 816 (void) write(ofd, ctime(&tvec), 24); 817 (void) write(ofd, "\n", 1); 818 } else { /* normal banner */ 819 (void) write(ofd, "\n\n\n", 3); 820 scan_out(ofd, name1, '\0'); 821 (void) write(ofd, "\n\n", 2); 822 scan_out(ofd, name2, '\0'); 823 if (class[0]) { 824 (void) write(ofd,"\n\n\n",3); 825 scan_out(ofd, class, '\0'); 826 } 827 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 828 (void) write(ofd, name2, strlen(name2)); 829 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 830 (void) write(ofd, ctime(&tvec), 24); 831 (void) write(ofd, "\n", 1); 832 } 833 if (!SF) 834 (void) write(ofd, FF, strlen(FF)); 835 tof = 1; 836 } 837 838 char * 839 scnline(key, p, c) 840 register char key, *p; 841 char c; 842 { 843 register scnwidth; 844 845 for (scnwidth = WIDTH; --scnwidth;) { 846 key <<= 1; 847 *p++ = key & 0200 ? c : BACKGND; 848 } 849 return (p); 850 } 851 852 #define TRC(q) (((q)-' ')&0177) 853 854 scan_out(scfd, scsp, dlm) 855 int scfd; 856 char *scsp, dlm; 857 { 858 register char *strp; 859 register nchrs, j; 860 char outbuf[LINELEN+1], *sp, c, cc; 861 int d, scnhgt; 862 extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 863 864 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 865 strp = &outbuf[0]; 866 sp = scsp; 867 for (nchrs = 0; ; ) { 868 d = dropit(c = TRC(cc = *sp++)); 869 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 870 for (j = WIDTH; --j;) 871 *strp++ = BACKGND; 872 else 873 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 874 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 875 break; 876 *strp++ = BACKGND; 877 *strp++ = BACKGND; 878 } 879 while (*--strp == BACKGND && strp >= outbuf) 880 ; 881 strp++; 882 *strp++ = '\n'; 883 (void) write(scfd, outbuf, strp-outbuf); 884 } 885 } 886 887 dropit(c) 888 char c; 889 { 890 switch(c) { 891 892 case TRC('_'): 893 case TRC(';'): 894 case TRC(','): 895 case TRC('g'): 896 case TRC('j'): 897 case TRC('p'): 898 case TRC('q'): 899 case TRC('y'): 900 return (DROP); 901 902 default: 903 return (0); 904 } 905 } 906 907 /* 908 * sendmail --- 909 * tell people about job completion 910 */ 911 sendmail(user, bombed) 912 char *user; 913 int bombed; 914 { 915 register int i; 916 int p[2], s; 917 register char *cp; 918 char buf[100]; 919 struct stat stb; 920 FILE *fp; 921 922 pipe(p); 923 if ((s = dofork(DORETURN)) == 0) { /* child */ 924 dup2(p[0], 0); 925 for (i = 3; i < NOFILE; i++) 926 (void) close(i); 927 if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 928 cp++; 929 else 930 cp = _PATH_SENDMAIL; 931 sprintf(buf, "%s@%s", user, fromhost); 932 execl(_PATH_SENDMAIL, cp, buf, 0); 933 exit(0); 934 } else if (s > 0) { /* parent */ 935 dup2(p[1], 1); 936 printf("To: %s@%s\n", user, fromhost); 937 printf("Subject: printer job\n\n"); 938 printf("Your printer job "); 939 if (*jobname) 940 printf("(%s) ", jobname); 941 switch (bombed) { 942 case OK: 943 printf("\ncompleted successfully\n"); 944 break; 945 default: 946 case FATALERR: 947 printf("\ncould not be printed\n"); 948 break; 949 case NOACCT: 950 printf("\ncould not be printed without an account on %s\n", host); 951 break; 952 case FILTERERR: 953 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 954 (fp = fopen(tempfile, "r")) == NULL) { 955 printf("\nwas printed but had some errors\n"); 956 break; 957 } 958 printf("\nwas printed but had the following errors:\n"); 959 while ((i = getc(fp)) != EOF) 960 putchar(i); 961 (void) fclose(fp); 962 break; 963 case ACCESS: 964 printf("\nwas not printed because it was not linked to the original file\n"); 965 } 966 fflush(stdout); 967 (void) close(1); 968 } 969 (void) close(p[0]); 970 (void) close(p[1]); 971 wait(&s); 972 } 973 974 /* 975 * dofork - fork with retries on failure 976 */ 977 dofork(action) 978 int action; 979 { 980 register int i, pid; 981 982 for (i = 0; i < 20; i++) { 983 if ((pid = fork()) < 0) { 984 sleep((unsigned)(i*i)); 985 continue; 986 } 987 /* 988 * Child should run as daemon instead of root 989 */ 990 if (pid == 0) 991 setuid(DU); 992 return(pid); 993 } 994 syslog(LOG_ERR, "can't fork"); 995 996 switch (action) { 997 case DORETURN: 998 return (-1); 999 default: 1000 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1001 /*FALL THRU*/ 1002 case DOABORT: 1003 exit(1); 1004 } 1005 /*NOTREACHED*/ 1006 } 1007 1008 /* 1009 * Kill child processes to abort current job. 1010 */ 1011 abortpr() 1012 { 1013 (void) unlink(tempfile); 1014 kill(0, SIGINT); 1015 if (ofilter > 0) 1016 kill(ofilter, SIGCONT); 1017 while (wait(0) > 0) 1018 ; 1019 exit(0); 1020 } 1021 1022 init() 1023 { 1024 int status; 1025 char *s; 1026 1027 if ((status = pgetent(line, printer)) < 0) { 1028 syslog(LOG_ERR, "can't open printer description file"); 1029 exit(1); 1030 } else if (status == 0) { 1031 syslog(LOG_ERR, "unknown printer: %s", printer); 1032 exit(1); 1033 } 1034 if ((LP = pgetstr("lp", &bp)) == NULL) 1035 LP = _PATH_DEFDEVLP; 1036 if ((RP = pgetstr("rp", &bp)) == NULL) 1037 RP = DEFLP; 1038 if ((LO = pgetstr("lo", &bp)) == NULL) 1039 LO = DEFLOCK; 1040 if ((ST = pgetstr("st", &bp)) == NULL) 1041 ST = DEFSTAT; 1042 if ((LF = pgetstr("lf", &bp)) == NULL) 1043 LF = _PATH_CONSOLE; 1044 if ((SD = pgetstr("sd", &bp)) == NULL) 1045 SD = _PATH_DEFSPOOL; 1046 if ((DU = pgetnum("du")) < 0) 1047 DU = DEFUID; 1048 if ((FF = pgetstr("ff", &bp)) == NULL) 1049 FF = DEFFF; 1050 if ((PW = pgetnum("pw")) < 0) 1051 PW = DEFWIDTH; 1052 sprintf(&width[2], "%d", PW); 1053 if ((PL = pgetnum("pl")) < 0) 1054 PL = DEFLENGTH; 1055 sprintf(&length[2], "%d", PL); 1056 if ((PX = pgetnum("px")) < 0) 1057 PX = 0; 1058 sprintf(&pxwidth[2], "%d", PX); 1059 if ((PY = pgetnum("py")) < 0) 1060 PY = 0; 1061 sprintf(&pxlength[2], "%d", PY); 1062 RM = pgetstr("rm", &bp); 1063 if (s = checkremote()) 1064 syslog(LOG_WARNING, s); 1065 1066 AF = pgetstr("af", &bp); 1067 OF = pgetstr("of", &bp); 1068 IF = pgetstr("if", &bp); 1069 RF = pgetstr("rf", &bp); 1070 TF = pgetstr("tf", &bp); 1071 NF = pgetstr("nf", &bp); 1072 DF = pgetstr("df", &bp); 1073 GF = pgetstr("gf", &bp); 1074 VF = pgetstr("vf", &bp); 1075 CF = pgetstr("cf", &bp); 1076 TR = pgetstr("tr", &bp); 1077 RS = pgetflag("rs"); 1078 SF = pgetflag("sf"); 1079 SH = pgetflag("sh"); 1080 SB = pgetflag("sb"); 1081 HL = pgetflag("hl"); 1082 RW = pgetflag("rw"); 1083 BR = pgetnum("br"); 1084 if ((FC = pgetnum("fc")) < 0) 1085 FC = 0; 1086 if ((FS = pgetnum("fs")) < 0) 1087 FS = 0; 1088 if ((XC = pgetnum("xc")) < 0) 1089 XC = 0; 1090 if ((XS = pgetnum("xs")) < 0) 1091 XS = 0; 1092 tof = !pgetflag("fo"); 1093 } 1094 1095 /* 1096 * Acquire line printer or remote connection. 1097 */ 1098 openpr() 1099 { 1100 register int i, n; 1101 int resp; 1102 1103 if (!sendtorem && *LP) { 1104 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1105 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1106 if (pfd >= 0) 1107 break; 1108 if (errno == ENOENT) { 1109 syslog(LOG_ERR, "%s: %m", LP); 1110 exit(1); 1111 } 1112 if (i == 1) 1113 status("waiting for %s to become ready (offline ?)", printer); 1114 sleep(i); 1115 } 1116 if (isatty(pfd)) 1117 setty(); 1118 status("%s is ready and printing", printer); 1119 } else if (RM != NULL) { 1120 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1121 resp = -1; 1122 pfd = getport(RM); 1123 if (pfd >= 0) { 1124 (void) sprintf(line, "\2%s\n", RP); 1125 n = strlen(line); 1126 if (write(pfd, line, n) == n && 1127 (resp = response()) == '\0') 1128 break; 1129 (void) close(pfd); 1130 } 1131 if (i == 1) { 1132 if (resp < 0) 1133 status("waiting for %s to come up", RM); 1134 else { 1135 status("waiting for queue to be enabled on %s", RM); 1136 i = 256; 1137 } 1138 } 1139 sleep(i); 1140 } 1141 status("sending to %s", RM); 1142 remote = 1; 1143 } else { 1144 syslog(LOG_ERR, "%s: no line printer device or host name", 1145 printer); 1146 exit(1); 1147 } 1148 /* 1149 * Start up an output filter, if needed. 1150 */ 1151 if (!remote && OF) { 1152 int p[2]; 1153 char *cp; 1154 1155 pipe(p); 1156 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1157 dup2(p[0], 0); /* pipe is std in */ 1158 dup2(pfd, 1); /* printer is std out */ 1159 for (i = 3; i < NOFILE; i++) 1160 (void) close(i); 1161 if ((cp = rindex(OF, '/')) == NULL) 1162 cp = OF; 1163 else 1164 cp++; 1165 execl(OF, cp, width, length, 0); 1166 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1167 exit(1); 1168 } 1169 (void) close(p[0]); /* close input side */ 1170 ofd = p[1]; /* use pipe for output */ 1171 } else { 1172 ofd = pfd; 1173 ofilter = 0; 1174 } 1175 } 1176 1177 struct bauds { 1178 int baud; 1179 int speed; 1180 } bauds[] = { 1181 50, B50, 1182 75, B75, 1183 110, B110, 1184 134, B134, 1185 150, B150, 1186 200, B200, 1187 300, B300, 1188 600, B600, 1189 1200, B1200, 1190 1800, B1800, 1191 2400, B2400, 1192 4800, B4800, 1193 9600, B9600, 1194 19200, EXTA, 1195 38400, EXTB, 1196 0, 0 1197 }; 1198 1199 /* 1200 * setup tty lines. 1201 */ 1202 setty() 1203 { 1204 struct sgttyb ttybuf; 1205 register struct bauds *bp; 1206 1207 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1208 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1209 exit(1); 1210 } 1211 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1212 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1213 exit(1); 1214 } 1215 if (BR > 0) { 1216 for (bp = bauds; bp->baud; bp++) 1217 if (BR == bp->baud) 1218 break; 1219 if (!bp->baud) { 1220 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1221 exit(1); 1222 } 1223 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1224 } 1225 ttybuf.sg_flags &= ~FC; 1226 ttybuf.sg_flags |= FS; 1227 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1228 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1229 exit(1); 1230 } 1231 if (XC) { 1232 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1233 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1234 exit(1); 1235 } 1236 } 1237 if (XS) { 1238 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1239 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1240 exit(1); 1241 } 1242 } 1243 } 1244 1245 /*VARARGS1*/ 1246 status(msg, a1, a2, a3) 1247 char *msg; 1248 { 1249 register int fd; 1250 char buf[BUFSIZ]; 1251 1252 umask(0); 1253 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1254 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1255 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1256 exit(1); 1257 } 1258 ftruncate(fd, 0); 1259 sprintf(buf, msg, a1, a2, a3); 1260 strcat(buf, "\n"); 1261 (void) write(fd, buf, strlen(buf)); 1262 (void) close(fd); 1263 } 1264