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