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