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