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