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