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