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