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