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