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 for (n = 3; n < NOFILE; n++) 542 (void) close(n); 543 execl(_PATH_PR, "pr", width, length, 544 "-h", *title ? title : " ", "-F", 0); 545 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 546 exit(2); 547 } 548 (void) close(p[1]); /* close output side */ 549 (void) close(fi); 550 if (prchild < 0) { 551 prchild = 0; 552 (void) close(p[0]); 553 return(ERROR); 554 } 555 fi = p[0]; /* use pipe for input */ 556 case 'f': /* print plain text file */ 557 prog = IF; 558 av[1] = width; 559 av[2] = length; 560 av[3] = indent; 561 n = 4; 562 break; 563 case 'l': /* like 'f' but pass control characters */ 564 prog = IF; 565 av[1] = "-c"; 566 av[2] = width; 567 av[3] = length; 568 av[4] = indent; 569 n = 5; 570 break; 571 case 'r': /* print a fortran text file */ 572 prog = RF; 573 av[1] = width; 574 av[2] = length; 575 n = 3; 576 break; 577 case 't': /* print troff output */ 578 case 'n': /* print ditroff output */ 579 case 'd': /* print tex output */ 580 (void) unlink(".railmag"); 581 if ((fo = creat(".railmag", FILMOD)) < 0) { 582 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 583 (void) unlink(".railmag"); 584 } else { 585 for (n = 0; n < 4; n++) { 586 if (fonts[n][0] != '/') 587 (void) write(fo, _PATH_VFONT, 588 sizeof(_PATH_VFONT) - 1); 589 (void) write(fo, fonts[n], strlen(fonts[n])); 590 (void) write(fo, "\n", 1); 591 } 592 (void) close(fo); 593 } 594 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 595 av[1] = pxwidth; 596 av[2] = pxlength; 597 n = 3; 598 break; 599 case 'c': /* print cifplot output */ 600 prog = CF; 601 av[1] = pxwidth; 602 av[2] = pxlength; 603 n = 3; 604 break; 605 case 'g': /* print plot(1G) output */ 606 prog = GF; 607 av[1] = pxwidth; 608 av[2] = pxlength; 609 n = 3; 610 break; 611 case 'v': /* print raster output */ 612 prog = VF; 613 av[1] = pxwidth; 614 av[2] = pxlength; 615 n = 3; 616 break; 617 default: 618 (void) close(fi); 619 syslog(LOG_ERR, "%s: illegal format character '%c'", 620 printer, format); 621 return(ERROR); 622 } 623 if ((av[0] = rindex(prog, '/')) != NULL) 624 av[0]++; 625 else 626 av[0] = prog; 627 av[n++] = "-n"; 628 av[n++] = logname; 629 av[n++] = "-h"; 630 av[n++] = fromhost; 631 av[n++] = AF; 632 av[n] = 0; 633 fo = pfd; 634 if (ofilter > 0) { /* stop output filter */ 635 write(ofd, "\031\1", 2); 636 while ((pid = 637 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 638 ; 639 if (status.w_stopval != WSTOPPED) { 640 (void) close(fi); 641 syslog(LOG_WARNING, "%s: output filter died (%d)", 642 printer, status.w_retcode); 643 return(REPRINT); 644 } 645 stopped++; 646 } 647 start: 648 if ((child = dofork(DORETURN)) == 0) { /* child */ 649 dup2(fi, 0); 650 dup2(fo, 1); 651 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 652 if (n >= 0) 653 dup2(n, 2); 654 for (n = 3; n < NOFILE; n++) 655 (void) close(n); 656 execv(prog, av); 657 syslog(LOG_ERR, "cannot execv %s", prog); 658 exit(2); 659 } 660 (void) close(fi); 661 if (child < 0) 662 status.w_retcode = 100; 663 else 664 while ((pid = wait((int *)&status)) > 0 && pid != child) 665 ; 666 child = 0; 667 prchild = 0; 668 if (stopped) { /* restart output filter */ 669 if (kill(ofilter, SIGCONT) < 0) { 670 syslog(LOG_ERR, "cannot restart output filter"); 671 exit(1); 672 } 673 } 674 tof = 0; 675 676 /* Copy filter output to "lf" logfile */ 677 if (fp = fopen(tempfile, "r")) { 678 while (fgets(buf, sizeof(buf), fp)) 679 fputs(buf, stderr); 680 fclose(fp); 681 } 682 683 if (!WIFEXITED(status)) { 684 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 685 printer, format, status.w_termsig); 686 return(ERROR); 687 } 688 switch (status.w_retcode) { 689 case 0: 690 tof = 1; 691 return(OK); 692 case 1: 693 return(REPRINT); 694 default: 695 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 696 printer, format, status.w_retcode); 697 case 2: 698 return(ERROR); 699 } 700 } 701 702 /* 703 * Send the daemon control file (cf) and any data files. 704 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 705 * 0 if all is well. 706 */ 707 static int 708 sendit(file) 709 char *file; 710 { 711 register int i, err = OK; 712 char *cp, last[BUFSIZ]; 713 714 /* 715 * open control file 716 */ 717 if ((cfp = fopen(file, "r")) == NULL) 718 return(OK); 719 /* 720 * read the control file for work to do 721 * 722 * file format -- first character in the line is a command 723 * rest of the line is the argument. 724 * commands of interest are: 725 * 726 * a-z -- "file name" name of file to print 727 * U -- "unlink" name of file to remove 728 * (after we print it. (Pass 2 only)). 729 */ 730 731 /* 732 * pass 1 733 */ 734 while (getline(cfp)) { 735 again: 736 if (line[0] == 'S') { 737 cp = line+1; 738 i = 0; 739 while (*cp >= '0' && *cp <= '9') 740 i = i * 10 + (*cp++ - '0'); 741 fdev = i; 742 cp++; 743 i = 0; 744 while (*cp >= '0' && *cp <= '9') 745 i = i * 10 + (*cp++ - '0'); 746 fino = i; 747 continue; 748 } 749 if (line[0] >= 'a' && line[0] <= 'z') { 750 strcpy(last, line); 751 while (i = getline(cfp)) 752 if (strcmp(last, line)) 753 break; 754 switch (sendfile('\3', last+1)) { 755 case OK: 756 if (i) 757 goto again; 758 break; 759 case REPRINT: 760 (void) fclose(cfp); 761 return(REPRINT); 762 case ACCESS: 763 sendmail(logname, ACCESS); 764 case ERROR: 765 err = ERROR; 766 } 767 break; 768 } 769 } 770 if (err == OK && sendfile('\2', file) > 0) { 771 (void) fclose(cfp); 772 return(REPRINT); 773 } 774 /* 775 * pass 2 776 */ 777 fseek(cfp, 0L, 0); 778 while (getline(cfp)) 779 if (line[0] == 'U') 780 (void) unlink(line+1); 781 /* 782 * clean-up in case another control file exists 783 */ 784 (void) fclose(cfp); 785 (void) unlink(file); 786 return(err); 787 } 788 789 /* 790 * Send a data file to the remote machine and spool it. 791 * Return positive if we should try resending. 792 */ 793 static int 794 sendfile(type, file) 795 int type; 796 char *file; 797 { 798 register int f, i, amt; 799 struct stat stb; 800 char buf[BUFSIZ]; 801 int sizerr, resp; 802 803 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 804 return(ERROR); 805 /* 806 * Check to see if data file is a symbolic link. If so, it should 807 * still point to the same file or someone is trying to print something 808 * he shouldn't. 809 */ 810 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 811 (stb.st_dev != fdev || stb.st_ino != fino)) 812 return(ACCESS); 813 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 814 amt = strlen(buf); 815 for (i = 0; ; i++) { 816 if (write(pfd, buf, amt) != amt || 817 (resp = response()) < 0 || resp == '\1') { 818 (void) close(f); 819 return(REPRINT); 820 } else if (resp == '\0') 821 break; 822 if (i == 0) 823 pstatus("no space on remote; waiting for queue to drain"); 824 if (i == 10) 825 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 826 printer, RM); 827 sleep(5 * 60); 828 } 829 if (i) 830 pstatus("sending to %s", RM); 831 sizerr = 0; 832 for (i = 0; i < stb.st_size; i += BUFSIZ) { 833 amt = BUFSIZ; 834 if (i + amt > stb.st_size) 835 amt = stb.st_size - i; 836 if (sizerr == 0 && read(f, buf, amt) != amt) 837 sizerr = 1; 838 if (write(pfd, buf, amt) != amt) { 839 (void) close(f); 840 return(REPRINT); 841 } 842 } 843 844 845 846 847 (void) close(f); 848 if (sizerr) { 849 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 850 /* tell recvjob to ignore this file */ 851 (void) write(pfd, "\1", 1); 852 return(ERROR); 853 } 854 if (write(pfd, "", 1) != 1 || response()) 855 return(REPRINT); 856 return(OK); 857 } 858 859 /* 860 * Check to make sure there have been no errors and that both programs 861 * are in sync with eachother. 862 * Return non-zero if the connection was lost. 863 */ 864 static char 865 response() 866 { 867 char resp; 868 869 if (read(pfd, &resp, 1) != 1) { 870 syslog(LOG_INFO, "%s: lost connection", printer); 871 return(-1); 872 } 873 return(resp); 874 } 875 876 /* 877 * Banner printing stuff 878 */ 879 static void 880 banner(name1, name2) 881 char *name1, *name2; 882 { 883 time_t tvec; 884 extern char *ctime(); 885 886 time(&tvec); 887 if (!SF && !tof) 888 (void) write(ofd, FF, strlen(FF)); 889 if (SB) { /* short banner only */ 890 if (class[0]) { 891 (void) write(ofd, class, strlen(class)); 892 (void) write(ofd, ":", 1); 893 } 894 (void) write(ofd, name1, strlen(name1)); 895 (void) write(ofd, " Job: ", 7); 896 (void) write(ofd, name2, strlen(name2)); 897 (void) write(ofd, " Date: ", 8); 898 (void) write(ofd, ctime(&tvec), 24); 899 (void) write(ofd, "\n", 1); 900 } else { /* normal banner */ 901 (void) write(ofd, "\n\n\n", 3); 902 scan_out(ofd, name1, '\0'); 903 (void) write(ofd, "\n\n", 2); 904 scan_out(ofd, name2, '\0'); 905 if (class[0]) { 906 (void) write(ofd,"\n\n\n",3); 907 scan_out(ofd, class, '\0'); 908 } 909 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 910 (void) write(ofd, name2, strlen(name2)); 911 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 912 (void) write(ofd, ctime(&tvec), 24); 913 (void) write(ofd, "\n", 1); 914 } 915 if (!SF) 916 (void) write(ofd, FF, strlen(FF)); 917 tof = 1; 918 } 919 920 static char * 921 scnline(key, p, c) 922 register int key; 923 register char *p; 924 int c; 925 { 926 register scnwidth; 927 928 for (scnwidth = WIDTH; --scnwidth;) { 929 key <<= 1; 930 *p++ = key & 0200 ? c : BACKGND; 931 } 932 return (p); 933 } 934 935 #define TRC(q) (((q)-' ')&0177) 936 937 static void 938 scan_out(scfd, scsp, dlm) 939 int scfd, dlm; 940 char *scsp; 941 { 942 register char *strp; 943 register nchrs, j; 944 char outbuf[LINELEN+1], *sp, c, cc; 945 int d, scnhgt; 946 extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 947 948 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 949 strp = &outbuf[0]; 950 sp = scsp; 951 for (nchrs = 0; ; ) { 952 d = dropit(c = TRC(cc = *sp++)); 953 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 954 for (j = WIDTH; --j;) 955 *strp++ = BACKGND; 956 else 957 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 958 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 959 break; 960 *strp++ = BACKGND; 961 *strp++ = BACKGND; 962 } 963 while (*--strp == BACKGND && strp >= outbuf) 964 ; 965 strp++; 966 *strp++ = '\n'; 967 (void) write(scfd, outbuf, strp-outbuf); 968 } 969 } 970 971 static int 972 dropit(c) 973 int c; 974 { 975 switch(c) { 976 977 case TRC('_'): 978 case TRC(';'): 979 case TRC(','): 980 case TRC('g'): 981 case TRC('j'): 982 case TRC('p'): 983 case TRC('q'): 984 case TRC('y'): 985 return (DROP); 986 987 default: 988 return (0); 989 } 990 } 991 992 /* 993 * sendmail --- 994 * tell people about job completion 995 */ 996 static void 997 sendmail(user, bombed) 998 char *user; 999 int bombed; 1000 { 1001 register int i; 1002 int p[2], s; 1003 register char *cp; 1004 char buf[100]; 1005 struct stat stb; 1006 FILE *fp; 1007 1008 pipe(p); 1009 if ((s = dofork(DORETURN)) == 0) { /* child */ 1010 dup2(p[0], 0); 1011 for (i = 3; i < NOFILE; i++) 1012 (void) close(i); 1013 if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 1014 cp++; 1015 else 1016 cp = _PATH_SENDMAIL; 1017 sprintf(buf, "%s@%s", user, fromhost); 1018 execl(_PATH_SENDMAIL, cp, buf, 0); 1019 exit(0); 1020 } else if (s > 0) { /* parent */ 1021 dup2(p[1], 1); 1022 printf("To: %s@%s\n", user, fromhost); 1023 printf("Subject: printer job\n\n"); 1024 printf("Your printer job "); 1025 if (*jobname) 1026 printf("(%s) ", jobname); 1027 switch (bombed) { 1028 case OK: 1029 printf("\ncompleted successfully\n"); 1030 break; 1031 default: 1032 case FATALERR: 1033 printf("\ncould not be printed\n"); 1034 break; 1035 case NOACCT: 1036 printf("\ncould not be printed without an account on %s\n", host); 1037 break; 1038 case FILTERERR: 1039 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1040 (fp = fopen(tempfile, "r")) == NULL) { 1041 printf("\nwas printed but had some errors\n"); 1042 break; 1043 } 1044 printf("\nwas printed but had the following errors:\n"); 1045 while ((i = getc(fp)) != EOF) 1046 putchar(i); 1047 (void) fclose(fp); 1048 break; 1049 case ACCESS: 1050 printf("\nwas not printed because it was not linked to the original file\n"); 1051 } 1052 fflush(stdout); 1053 (void) close(1); 1054 } 1055 (void) close(p[0]); 1056 (void) close(p[1]); 1057 wait(&s); 1058 } 1059 1060 /* 1061 * dofork - fork with retries on failure 1062 */ 1063 static int 1064 dofork(action) 1065 int action; 1066 { 1067 register int i, pid; 1068 1069 for (i = 0; i < 20; i++) { 1070 if ((pid = fork()) < 0) { 1071 sleep((unsigned)(i*i)); 1072 continue; 1073 } 1074 /* 1075 * Child should run as daemon instead of root 1076 */ 1077 if (pid == 0) 1078 setuid(DU); 1079 return(pid); 1080 } 1081 syslog(LOG_ERR, "can't fork"); 1082 1083 switch (action) { 1084 case DORETURN: 1085 return (-1); 1086 default: 1087 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1088 /*FALL THRU*/ 1089 case DOABORT: 1090 exit(1); 1091 } 1092 /*NOTREACHED*/ 1093 } 1094 1095 /* 1096 * Kill child processes to abort current job. 1097 */ 1098 static void 1099 abortpr(signo) 1100 int signo; 1101 { 1102 (void) unlink(tempfile); 1103 kill(0, SIGINT); 1104 if (ofilter > 0) 1105 kill(ofilter, SIGCONT); 1106 while (wait(NULL) > 0) 1107 ; 1108 exit(0); 1109 } 1110 1111 static void 1112 init() 1113 { 1114 int status; 1115 char *s; 1116 1117 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1118 syslog(LOG_ERR, "can't open printer description file"); 1119 exit(1); 1120 } else if (status == -1) { 1121 syslog(LOG_ERR, "unknown printer: %s", printer); 1122 exit(1); 1123 } else if (status == -3) 1124 fatal("potential reference loop detected in printcap file"); 1125 1126 if (cgetstr(bp, "lp", &LP) == -1) 1127 LP = _PATH_DEFDEVLP; 1128 if (cgetstr(bp, "rp", &RP) == -1) 1129 RP = DEFLP; 1130 if (cgetstr(bp, "lo", &LO) == -1) 1131 LO = DEFLOCK; 1132 if (cgetstr(bp, "st", &ST) == -1) 1133 ST = DEFSTAT; 1134 if (cgetstr(bp, "lf", &LF) == -1) 1135 LF = _PATH_CONSOLE; 1136 if (cgetstr(bp, "sd", &SD) == -1) 1137 SD = _PATH_DEFSPOOL; 1138 if (cgetnum(bp, "du", &DU) < 0) 1139 DU = DEFUID; 1140 if (cgetstr(bp,"ff", &FF) == -1) 1141 FF = DEFFF; 1142 if (cgetnum(bp, "pw", &PW) < 0) 1143 PW = DEFWIDTH; 1144 sprintf(&width[2], "%d", PW); 1145 if (cgetnum(bp, "pl", &PL) < 0) 1146 PL = DEFLENGTH; 1147 sprintf(&length[2], "%d", PL); 1148 if (cgetnum(bp,"px", &PX) < 0) 1149 PX = 0; 1150 sprintf(&pxwidth[2], "%d", PX); 1151 if (cgetnum(bp, "py", &PY) < 0) 1152 PY = 0; 1153 sprintf(&pxlength[2], "%d", PY); 1154 cgetstr(bp, "rm", &RM); 1155 if (s = checkremote()) 1156 syslog(LOG_WARNING, s); 1157 1158 cgetstr(bp, "af", &AF); 1159 cgetstr(bp, "of", &OF); 1160 cgetstr(bp, "if", &IF); 1161 cgetstr(bp, "rf", &RF); 1162 cgetstr(bp, "tf", &TF); 1163 cgetstr(bp, "nf", &NF); 1164 cgetstr(bp, "df", &DF); 1165 cgetstr(bp, "gf", &GF); 1166 cgetstr(bp, "vf", &VF); 1167 cgetstr(bp, "cf", &CF); 1168 cgetstr(bp, "tr", &TR); 1169 1170 RS = (cgetcap(bp, "rs", ':') != NULL); 1171 SF = (cgetcap(bp, "sf", ':') != NULL); 1172 SH = (cgetcap(bp, "sh", ':') != NULL); 1173 SB = (cgetcap(bp, "sb", ':') != NULL); 1174 HL = (cgetcap(bp, "hl", ':') != NULL); 1175 RW = (cgetcap(bp, "rw", ':') != NULL); 1176 1177 cgetnum(bp, "br", &BR); 1178 if (cgetnum(bp, "fc", &FC) < 0) 1179 FC = 0; 1180 if (cgetnum(bp, "fs", &FS) < 0) 1181 FS = 0; 1182 if (cgetnum(bp, "xc", &XC) < 0) 1183 XC = 0; 1184 if (cgetnum(bp, "xs", &XS) < 0) 1185 XS = 0; 1186 1187 tof = (cgetcap(bp, "fo", ':') == NULL); 1188 } 1189 1190 /* 1191 * Acquire line printer or remote connection. 1192 */ 1193 static void 1194 openpr() 1195 { 1196 register int i, n; 1197 int resp; 1198 1199 if (!sendtorem && *LP) { 1200 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1201 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1202 if (pfd >= 0) 1203 break; 1204 if (errno == ENOENT) { 1205 syslog(LOG_ERR, "%s: %m", LP); 1206 exit(1); 1207 } 1208 if (i == 1) 1209 pstatus("waiting for %s to become ready (offline ?)", printer); 1210 sleep(i); 1211 } 1212 if (isatty(pfd)) 1213 setty(); 1214 pstatus("%s is ready and printing", printer); 1215 } else if (RM != NULL) { 1216 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1217 resp = -1; 1218 pfd = getport(RM); 1219 if (pfd >= 0) { 1220 (void) sprintf(line, "\2%s\n", RP); 1221 n = strlen(line); 1222 if (write(pfd, line, n) == n && 1223 (resp = response()) == '\0') 1224 break; 1225 (void) close(pfd); 1226 } 1227 if (i == 1) { 1228 if (resp < 0) 1229 pstatus("waiting for %s to come up", RM); 1230 else { 1231 pstatus("waiting for queue to be enabled on %s", RM); 1232 i = 256; 1233 } 1234 } 1235 sleep(i); 1236 } 1237 pstatus("sending to %s", RM); 1238 remote = 1; 1239 } else { 1240 syslog(LOG_ERR, "%s: no line printer device or host name", 1241 printer); 1242 exit(1); 1243 } 1244 /* 1245 * Start up an output filter, if needed. 1246 */ 1247 if (!remote && OF) { 1248 int p[2]; 1249 char *cp; 1250 1251 pipe(p); 1252 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1253 dup2(p[0], 0); /* pipe is std in */ 1254 dup2(pfd, 1); /* printer is std out */ 1255 for (i = 3; i < NOFILE; i++) 1256 (void) close(i); 1257 if ((cp = rindex(OF, '/')) == NULL) 1258 cp = OF; 1259 else 1260 cp++; 1261 execl(OF, cp, width, length, 0); 1262 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1263 exit(1); 1264 } 1265 (void) close(p[0]); /* close input side */ 1266 ofd = p[1]; /* use pipe for output */ 1267 } else { 1268 ofd = pfd; 1269 ofilter = 0; 1270 } 1271 } 1272 1273 struct bauds { 1274 int baud; 1275 int speed; 1276 } bauds[] = { 1277 50, B50, 1278 75, B75, 1279 110, B110, 1280 134, B134, 1281 150, B150, 1282 200, B200, 1283 300, B300, 1284 600, B600, 1285 1200, B1200, 1286 1800, B1800, 1287 2400, B2400, 1288 4800, B4800, 1289 9600, B9600, 1290 19200, EXTA, 1291 38400, EXTB, 1292 0, 0 1293 }; 1294 1295 /* 1296 * setup tty lines. 1297 */ 1298 static void 1299 setty() 1300 { 1301 struct sgttyb ttybuf; 1302 register struct bauds *bp; 1303 1304 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1305 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1306 exit(1); 1307 } 1308 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1309 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1310 exit(1); 1311 } 1312 if (BR > 0) { 1313 for (bp = bauds; bp->baud; bp++) 1314 if (BR == bp->baud) 1315 break; 1316 if (!bp->baud) { 1317 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1318 exit(1); 1319 } 1320 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1321 } 1322 ttybuf.sg_flags &= ~FC; 1323 ttybuf.sg_flags |= FS; 1324 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1325 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1326 exit(1); 1327 } 1328 if (XC) { 1329 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1330 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1331 exit(1); 1332 } 1333 } 1334 if (XS) { 1335 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1336 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1337 exit(1); 1338 } 1339 } 1340 } 1341 1342 #if __STDC__ 1343 #include <stdarg.h> 1344 #else 1345 #include <varargs.h> 1346 #endif 1347 1348 void 1349 #if __STDC__ 1350 pstatus(const char *msg, ...) 1351 #else 1352 pstatus(msg, va_alist) 1353 char *msg; 1354 va_dcl 1355 #endif 1356 { 1357 register int fd; 1358 char buf[BUFSIZ]; 1359 va_list ap; 1360 #if __STDC__ 1361 va_start(ap, msg); 1362 #else 1363 va_start(ap); 1364 #endif 1365 1366 umask(0); 1367 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1368 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1369 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1370 exit(1); 1371 } 1372 ftruncate(fd, 0); 1373 (void)vsnprintf(buf, sizeof(buf), msg, ap); 1374 va_end(ap); 1375 strcat(buf, "\n"); 1376 (void) write(fd, buf, strlen(buf)); 1377 (void) close(fd); 1378 } 1379