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