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