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.9 (Berkeley) 08/22/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 char *s; 1025 1026 if ((status = pgetent(line, printer)) < 0) { 1027 syslog(LOG_ERR, "can't open printer description file"); 1028 exit(1); 1029 } else if (status == 0) { 1030 syslog(LOG_ERR, "unknown printer: %s", printer); 1031 exit(1); 1032 } 1033 if ((LP = pgetstr("lp", &bp)) == NULL) 1034 LP = _PATH_DEFDEVLP; 1035 if ((RP = pgetstr("rp", &bp)) == NULL) 1036 RP = DEFLP; 1037 if ((LO = pgetstr("lo", &bp)) == NULL) 1038 LO = DEFLOCK; 1039 if ((ST = pgetstr("st", &bp)) == NULL) 1040 ST = DEFSTAT; 1041 if ((LF = pgetstr("lf", &bp)) == NULL) 1042 LF = _PATH_CONSOLE; 1043 if ((SD = pgetstr("sd", &bp)) == NULL) 1044 SD = _PATH_DEFSPOOL; 1045 if ((DU = pgetnum("du")) < 0) 1046 DU = DEFUID; 1047 if ((FF = pgetstr("ff", &bp)) == NULL) 1048 FF = DEFFF; 1049 if ((PW = pgetnum("pw")) < 0) 1050 PW = DEFWIDTH; 1051 sprintf(&width[2], "%d", PW); 1052 if ((PL = pgetnum("pl")) < 0) 1053 PL = DEFLENGTH; 1054 sprintf(&length[2], "%d", PL); 1055 if ((PX = pgetnum("px")) < 0) 1056 PX = 0; 1057 sprintf(&pxwidth[2], "%d", PX); 1058 if ((PY = pgetnum("py")) < 0) 1059 PY = 0; 1060 sprintf(&pxlength[2], "%d", PY); 1061 RM = pgetstr("rm", &bp); 1062 if (s = checkremote()) 1063 syslog(LOG_WARNING, s); 1064 1065 AF = pgetstr("af", &bp); 1066 OF = pgetstr("of", &bp); 1067 IF = pgetstr("if", &bp); 1068 RF = pgetstr("rf", &bp); 1069 TF = pgetstr("tf", &bp); 1070 NF = pgetstr("nf", &bp); 1071 DF = pgetstr("df", &bp); 1072 GF = pgetstr("gf", &bp); 1073 VF = pgetstr("vf", &bp); 1074 CF = pgetstr("cf", &bp); 1075 TR = pgetstr("tr", &bp); 1076 RS = pgetflag("rs"); 1077 SF = pgetflag("sf"); 1078 SH = pgetflag("sh"); 1079 SB = pgetflag("sb"); 1080 HL = pgetflag("hl"); 1081 RW = pgetflag("rw"); 1082 BR = pgetnum("br"); 1083 if ((FC = pgetnum("fc")) < 0) 1084 FC = 0; 1085 if ((FS = pgetnum("fs")) < 0) 1086 FS = 0; 1087 if ((XC = pgetnum("xc")) < 0) 1088 XC = 0; 1089 if ((XS = pgetnum("xs")) < 0) 1090 XS = 0; 1091 tof = !pgetflag("fo"); 1092 } 1093 1094 /* 1095 * Acquire line printer or remote connection. 1096 */ 1097 openpr() 1098 { 1099 register int i, n; 1100 int resp; 1101 1102 if (!sendtorem && *LP) { 1103 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1104 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1105 if (pfd >= 0) 1106 break; 1107 if (errno == ENOENT) { 1108 syslog(LOG_ERR, "%s: %m", LP); 1109 exit(1); 1110 } 1111 if (i == 1) 1112 status("waiting for %s to become ready (offline ?)", printer); 1113 sleep(i); 1114 } 1115 if (isatty(pfd)) 1116 setty(); 1117 status("%s is ready and printing", printer); 1118 } else if (RM != NULL) { 1119 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1120 resp = -1; 1121 pfd = getport(RM); 1122 if (pfd >= 0) { 1123 (void) sprintf(line, "\2%s\n", RP); 1124 n = strlen(line); 1125 if (write(pfd, line, n) == n && 1126 (resp = response()) == '\0') 1127 break; 1128 (void) close(pfd); 1129 } 1130 if (i == 1) { 1131 if (resp < 0) 1132 status("waiting for %s to come up", RM); 1133 else { 1134 status("waiting for queue to be enabled on %s", RM); 1135 i = 256; 1136 } 1137 } 1138 sleep(i); 1139 } 1140 status("sending to %s", RM); 1141 remote = 1; 1142 } else { 1143 syslog(LOG_ERR, "%s: no line printer device or host name", 1144 printer); 1145 exit(1); 1146 } 1147 /* 1148 * Start up an output filter, if needed. 1149 */ 1150 if (OF) { 1151 int p[2]; 1152 char *cp; 1153 1154 pipe(p); 1155 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1156 dup2(p[0], 0); /* pipe is std in */ 1157 dup2(pfd, 1); /* printer is std out */ 1158 for (i = 3; i < NOFILE; i++) 1159 (void) close(i); 1160 if ((cp = rindex(OF, '/')) == NULL) 1161 cp = OF; 1162 else 1163 cp++; 1164 execl(OF, cp, width, length, 0); 1165 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1166 exit(1); 1167 } 1168 (void) close(p[0]); /* close input side */ 1169 ofd = p[1]; /* use pipe for output */ 1170 } else { 1171 ofd = pfd; 1172 ofilter = 0; 1173 } 1174 } 1175 1176 struct bauds { 1177 int baud; 1178 int speed; 1179 } bauds[] = { 1180 50, B50, 1181 75, B75, 1182 110, B110, 1183 134, B134, 1184 150, B150, 1185 200, B200, 1186 300, B300, 1187 600, B600, 1188 1200, B1200, 1189 1800, B1800, 1190 2400, B2400, 1191 4800, B4800, 1192 9600, B9600, 1193 19200, EXTA, 1194 38400, EXTB, 1195 0, 0 1196 }; 1197 1198 /* 1199 * setup tty lines. 1200 */ 1201 setty() 1202 { 1203 struct sgttyb ttybuf; 1204 register struct bauds *bp; 1205 1206 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1207 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1208 exit(1); 1209 } 1210 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1211 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1212 exit(1); 1213 } 1214 if (BR > 0) { 1215 for (bp = bauds; bp->baud; bp++) 1216 if (BR == bp->baud) 1217 break; 1218 if (!bp->baud) { 1219 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1220 exit(1); 1221 } 1222 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1223 } 1224 ttybuf.sg_flags &= ~FC; 1225 ttybuf.sg_flags |= FS; 1226 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1227 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1228 exit(1); 1229 } 1230 if (XC) { 1231 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1232 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1233 exit(1); 1234 } 1235 } 1236 if (XS) { 1237 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1238 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1239 exit(1); 1240 } 1241 } 1242 } 1243 1244 /*VARARGS1*/ 1245 status(msg, a1, a2, a3) 1246 char *msg; 1247 { 1248 register int fd; 1249 char buf[BUFSIZ]; 1250 1251 umask(0); 1252 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1253 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1254 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1255 exit(1); 1256 } 1257 ftruncate(fd, 0); 1258 sprintf(buf, msg, a1, a2, a3); 1259 strcat(buf, "\n"); 1260 (void) write(fd, buf, strlen(buf)); 1261 (void) close(fd); 1262 } 1263