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