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