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