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