printjob.c revision 9821
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] = "-F"; 533 av[6] = 0; 534 fo = ofd; 535 goto start; 536 } 537 pipe(p); 538 if ((prchild = dofork(DORETURN)) == 0) { /* child */ 539 dup2(fi, 0); /* file is stdin */ 540 dup2(p[1], 1); /* pipe is stdout */ 541 closelog(); 542 for (n = 3; n < NOFILE; n++) 543 (void) close(n); 544 execl(_PATH_PR, "pr", width, length, 545 "-h", *title ? title : " ", "-F", 0); 546 openlog("lpd", LOG_PID, LOG_LPR); 547 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 548 exit(2); 549 } 550 (void) close(p[1]); /* close output side */ 551 (void) close(fi); 552 if (prchild < 0) { 553 prchild = 0; 554 (void) close(p[0]); 555 return(ERROR); 556 } 557 fi = p[0]; /* use pipe for input */ 558 case 'f': /* print plain text file */ 559 prog = IF; 560 av[1] = width; 561 av[2] = length; 562 av[3] = indent; 563 n = 4; 564 break; 565 case 'l': /* like 'f' but pass control characters */ 566 prog = IF; 567 av[1] = "-c"; 568 av[2] = width; 569 av[3] = length; 570 av[4] = indent; 571 n = 5; 572 break; 573 case 'r': /* print a fortran text file */ 574 prog = RF; 575 av[1] = width; 576 av[2] = length; 577 n = 3; 578 break; 579 case 't': /* print troff output */ 580 case 'n': /* print ditroff output */ 581 case 'd': /* print tex output */ 582 (void) unlink(".railmag"); 583 if ((fo = creat(".railmag", FILMOD)) < 0) { 584 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 585 (void) unlink(".railmag"); 586 } else { 587 for (n = 0; n < 4; n++) { 588 if (fonts[n][0] != '/') 589 (void) write(fo, _PATH_VFONT, 590 sizeof(_PATH_VFONT) - 1); 591 (void) write(fo, fonts[n], strlen(fonts[n])); 592 (void) write(fo, "\n", 1); 593 } 594 (void) close(fo); 595 } 596 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 597 av[1] = pxwidth; 598 av[2] = pxlength; 599 n = 3; 600 break; 601 case 'c': /* print cifplot output */ 602 prog = CF; 603 av[1] = pxwidth; 604 av[2] = pxlength; 605 n = 3; 606 break; 607 case 'g': /* print plot(1G) output */ 608 prog = GF; 609 av[1] = pxwidth; 610 av[2] = pxlength; 611 n = 3; 612 break; 613 case 'v': /* print raster output */ 614 prog = VF; 615 av[1] = pxwidth; 616 av[2] = pxlength; 617 n = 3; 618 break; 619 default: 620 (void) close(fi); 621 syslog(LOG_ERR, "%s: illegal format character '%c'", 622 printer, format); 623 return(ERROR); 624 } 625 if ((av[0] = rindex(prog, '/')) != NULL) 626 av[0]++; 627 else 628 av[0] = prog; 629 av[n++] = "-n"; 630 av[n++] = logname; 631 av[n++] = "-h"; 632 av[n++] = fromhost; 633 av[n++] = AF; 634 av[n] = 0; 635 fo = pfd; 636 if (ofilter > 0) { /* stop output filter */ 637 write(ofd, "\031\1", 2); 638 while ((pid = 639 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 640 ; 641 if (status.w_stopval != WSTOPPED) { 642 (void) close(fi); 643 syslog(LOG_WARNING, "%s: output filter died (%d)", 644 printer, status.w_retcode); 645 return(REPRINT); 646 } 647 stopped++; 648 } 649start: 650 if ((child = dofork(DORETURN)) == 0) { /* child */ 651 dup2(fi, 0); 652 dup2(fo, 1); 653 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 654 if (n >= 0) 655 dup2(n, 2); 656 closelog(); 657 for (n = 3; n < NOFILE; n++) 658 (void) close(n); 659 execv(prog, av); 660 openlog("lpd", LOG_PID, LOG_LPR); 661 syslog(LOG_ERR, "cannot execv %s", prog); 662 exit(2); 663 } 664 (void) close(fi); 665 if (child < 0) 666 status.w_retcode = 100; 667 else 668 while ((pid = wait((int *)&status)) > 0 && pid != child) 669 ; 670 child = 0; 671 prchild = 0; 672 if (stopped) { /* restart output filter */ 673 if (kill(ofilter, SIGCONT) < 0) { 674 syslog(LOG_ERR, "cannot restart output filter"); 675 exit(1); 676 } 677 } 678 tof = 0; 679 680 /* Copy filter output to "lf" logfile */ 681 if (fp = fopen(tempfile, "r")) { 682 while (fgets(buf, sizeof(buf), fp)) 683 fputs(buf, stderr); 684 fclose(fp); 685 } 686 687 if (!WIFEXITED(status)) { 688 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 689 printer, format, status.w_termsig); 690 return(ERROR); 691 } 692 switch (status.w_retcode) { 693 case 0: 694 tof = 1; 695 return(OK); 696 case 1: 697 return(REPRINT); 698 default: 699 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 700 printer, format, status.w_retcode); 701 case 2: 702 return(ERROR); 703 } 704} 705 706/* 707 * Send the daemon control file (cf) and any data files. 708 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 709 * 0 if all is well. 710 */ 711static int 712sendit(file) 713 char *file; 714{ 715 register int i, err = OK; 716 char *cp, last[BUFSIZ]; 717 718 /* 719 * open control file 720 */ 721 if ((cfp = fopen(file, "r")) == NULL) 722 return(OK); 723 /* 724 * read the control file for work to do 725 * 726 * file format -- first character in the line is a command 727 * rest of the line is the argument. 728 * commands of interest are: 729 * 730 * a-z -- "file name" name of file to print 731 * U -- "unlink" name of file to remove 732 * (after we print it. (Pass 2 only)). 733 */ 734 735 /* 736 * pass 1 737 */ 738 while (getline(cfp)) { 739 again: 740 if (line[0] == 'S') { 741 cp = line+1; 742 i = 0; 743 while (*cp >= '0' && *cp <= '9') 744 i = i * 10 + (*cp++ - '0'); 745 fdev = i; 746 cp++; 747 i = 0; 748 while (*cp >= '0' && *cp <= '9') 749 i = i * 10 + (*cp++ - '0'); 750 fino = i; 751 continue; 752 } 753 if (line[0] >= 'a' && line[0] <= 'z') { 754 strcpy(last, line); 755 while (i = getline(cfp)) 756 if (strcmp(last, line)) 757 break; 758 switch (sendfile('\3', last+1)) { 759 case OK: 760 if (i) 761 goto again; 762 break; 763 case REPRINT: 764 (void) fclose(cfp); 765 return(REPRINT); 766 case ACCESS: 767 sendmail(logname, ACCESS); 768 case ERROR: 769 err = ERROR; 770 } 771 break; 772 } 773 } 774 if (err == OK && sendfile('\2', file) > 0) { 775 (void) fclose(cfp); 776 return(REPRINT); 777 } 778 /* 779 * pass 2 780 */ 781 fseek(cfp, 0L, 0); 782 while (getline(cfp)) 783 if (line[0] == 'U') 784 (void) unlink(line+1); 785 /* 786 * clean-up in case another control file exists 787 */ 788 (void) fclose(cfp); 789 (void) unlink(file); 790 return(err); 791} 792 793/* 794 * Send a data file to the remote machine and spool it. 795 * Return positive if we should try resending. 796 */ 797static int 798sendfile(type, file) 799 int type; 800 char *file; 801{ 802 register int f, i, amt; 803 struct stat stb; 804 char buf[BUFSIZ]; 805 int sizerr, resp; 806 807 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 808 return(ERROR); 809 /* 810 * Check to see if data file is a symbolic link. If so, it should 811 * still point to the same file or someone is trying to print something 812 * he shouldn't. 813 */ 814 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 815 (stb.st_dev != fdev || stb.st_ino != fino)) 816 return(ACCESS); 817 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 818 amt = strlen(buf); 819 for (i = 0; ; i++) { 820 if (write(pfd, buf, amt) != amt || 821 (resp = response()) < 0 || resp == '\1') { 822 (void) close(f); 823 return(REPRINT); 824 } else if (resp == '\0') 825 break; 826 if (i == 0) 827 pstatus("no space on remote; waiting for queue to drain"); 828 if (i == 10) 829 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 830 printer, RM); 831 sleep(5 * 60); 832 } 833 if (i) 834 pstatus("sending to %s", RM); 835 sizerr = 0; 836 for (i = 0; i < stb.st_size; i += BUFSIZ) { 837 amt = BUFSIZ; 838 if (i + amt > stb.st_size) 839 amt = stb.st_size - i; 840 if (sizerr == 0 && read(f, buf, amt) != amt) 841 sizerr = 1; 842 if (write(pfd, buf, amt) != amt) { 843 (void) close(f); 844 return(REPRINT); 845 } 846 } 847 848 849 850 851 (void) close(f); 852 if (sizerr) { 853 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 854 /* tell recvjob to ignore this file */ 855 (void) write(pfd, "\1", 1); 856 return(ERROR); 857 } 858 if (write(pfd, "", 1) != 1 || response()) 859 return(REPRINT); 860 return(OK); 861} 862 863/* 864 * Check to make sure there have been no errors and that both programs 865 * are in sync with eachother. 866 * Return non-zero if the connection was lost. 867 */ 868static char 869response() 870{ 871 char resp; 872 873 if (read(pfd, &resp, 1) != 1) { 874 syslog(LOG_INFO, "%s: lost connection", printer); 875 return(-1); 876 } 877 return(resp); 878} 879 880/* 881 * Banner printing stuff 882 */ 883static void 884banner(name1, name2) 885 char *name1, *name2; 886{ 887 time_t tvec; 888 extern char *ctime(); 889 890 time(&tvec); 891 if (!SF && !tof) 892 (void) write(ofd, FF, strlen(FF)); 893 if (SB) { /* short banner only */ 894 if (class[0]) { 895 (void) write(ofd, class, strlen(class)); 896 (void) write(ofd, ":", 1); 897 } 898 (void) write(ofd, name1, strlen(name1)); 899 (void) write(ofd, " Job: ", 7); 900 (void) write(ofd, name2, strlen(name2)); 901 (void) write(ofd, " Date: ", 8); 902 (void) write(ofd, ctime(&tvec), 24); 903 (void) write(ofd, "\n", 1); 904 } else { /* normal banner */ 905 (void) write(ofd, "\n\n\n", 3); 906 scan_out(ofd, name1, '\0'); 907 (void) write(ofd, "\n\n", 2); 908 scan_out(ofd, name2, '\0'); 909 if (class[0]) { 910 (void) write(ofd,"\n\n\n",3); 911 scan_out(ofd, class, '\0'); 912 } 913 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 914 (void) write(ofd, name2, strlen(name2)); 915 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 916 (void) write(ofd, ctime(&tvec), 24); 917 (void) write(ofd, "\n", 1); 918 } 919 if (!SF) 920 (void) write(ofd, FF, strlen(FF)); 921 tof = 1; 922} 923 924static char * 925scnline(key, p, c) 926 register int key; 927 register char *p; 928 int c; 929{ 930 register scnwidth; 931 932 for (scnwidth = WIDTH; --scnwidth;) { 933 key <<= 1; 934 *p++ = key & 0200 ? c : BACKGND; 935 } 936 return (p); 937} 938 939#define TRC(q) (((q)-' ')&0177) 940 941static void 942scan_out(scfd, scsp, dlm) 943 int scfd, dlm; 944 char *scsp; 945{ 946 register char *strp; 947 register nchrs, j; 948 char outbuf[LINELEN+1], *sp, c, cc; 949 int d, scnhgt; 950 extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 951 952 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 953 strp = &outbuf[0]; 954 sp = scsp; 955 for (nchrs = 0; ; ) { 956 d = dropit(c = TRC(cc = *sp++)); 957 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 958 for (j = WIDTH; --j;) 959 *strp++ = BACKGND; 960 else 961 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 962 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 963 break; 964 *strp++ = BACKGND; 965 *strp++ = BACKGND; 966 } 967 while (*--strp == BACKGND && strp >= outbuf) 968 ; 969 strp++; 970 *strp++ = '\n'; 971 (void) write(scfd, outbuf, strp-outbuf); 972 } 973} 974 975static int 976dropit(c) 977 int c; 978{ 979 switch(c) { 980 981 case TRC('_'): 982 case TRC(';'): 983 case TRC(','): 984 case TRC('g'): 985 case TRC('j'): 986 case TRC('p'): 987 case TRC('q'): 988 case TRC('y'): 989 return (DROP); 990 991 default: 992 return (0); 993 } 994} 995 996/* 997 * sendmail --- 998 * tell people about job completion 999 */ 1000static void 1001sendmail(user, bombed) 1002 char *user; 1003 int bombed; 1004{ 1005 register int i; 1006 int p[2], s; 1007 register char *cp; 1008 char buf[100]; 1009 struct stat stb; 1010 FILE *fp; 1011 1012 pipe(p); 1013 if ((s = dofork(DORETURN)) == 0) { /* child */ 1014 dup2(p[0], 0); 1015 closelog(); 1016 for (i = 3; i < NOFILE; i++) 1017 (void) close(i); 1018 if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 1019 cp++; 1020 else 1021 cp = _PATH_SENDMAIL; 1022 sprintf(buf, "%s@%s", user, fromhost); 1023 execl(_PATH_SENDMAIL, cp, buf, 0); 1024 openlog("lpd", LOG_PID, LOG_LPR); 1025 syslog(LOG_ERR, "cannot execl %s", _PATH_SENDMAIL); 1026 exit(0); 1027 } else if (s > 0) { /* parent */ 1028 dup2(p[1], 1); 1029 printf("To: %s@%s\n", user, fromhost); 1030 printf("Subject: printer job\n\n"); 1031 printf("Your printer job "); 1032 if (*jobname) 1033 printf("(%s) ", jobname); 1034 switch (bombed) { 1035 case OK: 1036 printf("\ncompleted successfully\n"); 1037 break; 1038 default: 1039 case FATALERR: 1040 printf("\ncould not be printed\n"); 1041 break; 1042 case NOACCT: 1043 printf("\ncould not be printed without an account on %s\n", host); 1044 break; 1045 case FILTERERR: 1046 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1047 (fp = fopen(tempfile, "r")) == NULL) { 1048 printf("\nwas printed but had some errors\n"); 1049 break; 1050 } 1051 printf("\nwas printed but had the following errors:\n"); 1052 while ((i = getc(fp)) != EOF) 1053 putchar(i); 1054 (void) fclose(fp); 1055 break; 1056 case ACCESS: 1057 printf("\nwas not printed because it was not linked to the original file\n"); 1058 } 1059 fflush(stdout); 1060 (void) close(1); 1061 } 1062 (void) close(p[0]); 1063 (void) close(p[1]); 1064 wait(&s); 1065} 1066 1067/* 1068 * dofork - fork with retries on failure 1069 */ 1070static int 1071dofork(action) 1072 int action; 1073{ 1074 register int i, pid; 1075 1076 for (i = 0; i < 20; i++) { 1077 if ((pid = fork()) < 0) { 1078 sleep((unsigned)(i*i)); 1079 continue; 1080 } 1081 /* 1082 * Child should run as daemon instead of root 1083 */ 1084 if (pid == 0) 1085 setuid(DU); 1086 return(pid); 1087 } 1088 syslog(LOG_ERR, "can't fork"); 1089 1090 switch (action) { 1091 case DORETURN: 1092 return (-1); 1093 default: 1094 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1095 /*FALL THRU*/ 1096 case DOABORT: 1097 exit(1); 1098 } 1099 /*NOTREACHED*/ 1100} 1101 1102/* 1103 * Kill child processes to abort current job. 1104 */ 1105static void 1106abortpr(signo) 1107 int signo; 1108{ 1109 (void) unlink(tempfile); 1110 kill(0, SIGINT); 1111 if (ofilter > 0) 1112 kill(ofilter, SIGCONT); 1113 while (wait(NULL) > 0) 1114 ; 1115 exit(0); 1116} 1117 1118static void 1119init() 1120{ 1121 int status; 1122 char *s; 1123 1124 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1125 syslog(LOG_ERR, "can't open printer description file"); 1126 exit(1); 1127 } else if (status == -1) { 1128 syslog(LOG_ERR, "unknown printer: %s", printer); 1129 exit(1); 1130 } else if (status == -3) 1131 fatal("potential reference loop detected in printcap file"); 1132 1133 if (cgetstr(bp, "lp", &LP) == -1) 1134 LP = _PATH_DEFDEVLP; 1135 if (cgetstr(bp, "rp", &RP) == -1) 1136 RP = DEFLP; 1137 if (cgetstr(bp, "lo", &LO) == -1) 1138 LO = DEFLOCK; 1139 if (cgetstr(bp, "st", &ST) == -1) 1140 ST = DEFSTAT; 1141 if (cgetstr(bp, "lf", &LF) == -1) 1142 LF = _PATH_CONSOLE; 1143 if (cgetstr(bp, "sd", &SD) == -1) 1144 SD = _PATH_DEFSPOOL; 1145 if (cgetnum(bp, "du", &DU) < 0) 1146 DU = DEFUID; 1147 if (cgetstr(bp,"ff", &FF) == -1) 1148 FF = DEFFF; 1149 if (cgetnum(bp, "pw", &PW) < 0) 1150 PW = DEFWIDTH; 1151 sprintf(&width[2], "%d", PW); 1152 if (cgetnum(bp, "pl", &PL) < 0) 1153 PL = DEFLENGTH; 1154 sprintf(&length[2], "%d", PL); 1155 if (cgetnum(bp,"px", &PX) < 0) 1156 PX = 0; 1157 sprintf(&pxwidth[2], "%d", PX); 1158 if (cgetnum(bp, "py", &PY) < 0) 1159 PY = 0; 1160 sprintf(&pxlength[2], "%d", PY); 1161 cgetstr(bp, "rm", &RM); 1162 if (s = checkremote()) 1163 syslog(LOG_WARNING, s); 1164 1165 cgetstr(bp, "af", &AF); 1166 cgetstr(bp, "of", &OF); 1167 cgetstr(bp, "if", &IF); 1168 cgetstr(bp, "rf", &RF); 1169 cgetstr(bp, "tf", &TF); 1170 cgetstr(bp, "nf", &NF); 1171 cgetstr(bp, "df", &DF); 1172 cgetstr(bp, "gf", &GF); 1173 cgetstr(bp, "vf", &VF); 1174 cgetstr(bp, "cf", &CF); 1175 cgetstr(bp, "tr", &TR); 1176 1177 RS = (cgetcap(bp, "rs", ':') != NULL); 1178 SF = (cgetcap(bp, "sf", ':') != NULL); 1179 SH = (cgetcap(bp, "sh", ':') != NULL); 1180 SB = (cgetcap(bp, "sb", ':') != NULL); 1181 HL = (cgetcap(bp, "hl", ':') != NULL); 1182 RW = (cgetcap(bp, "rw", ':') != NULL); 1183 1184 cgetnum(bp, "br", &BR); 1185 if (cgetnum(bp, "fc", &FC) < 0) 1186 FC = 0; 1187 if (cgetnum(bp, "fs", &FS) < 0) 1188 FS = 0; 1189 if (cgetnum(bp, "xc", &XC) < 0) 1190 XC = 0; 1191 if (cgetnum(bp, "xs", &XS) < 0) 1192 XS = 0; 1193 1194 tof = (cgetcap(bp, "fo", ':') == NULL); 1195} 1196 1197/* 1198 * Acquire line printer or remote connection. 1199 */ 1200static void 1201openpr() 1202{ 1203 register int i, n; 1204 int resp; 1205 1206 if (!sendtorem && *LP) { 1207 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1208 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1209 if (pfd >= 0) 1210 break; 1211 if (errno == ENOENT) { 1212 syslog(LOG_ERR, "%s: %m", LP); 1213 exit(1); 1214 } 1215 if (i == 1) 1216 pstatus("waiting for %s to become ready (offline ?)", printer); 1217 sleep(i); 1218 } 1219 if (isatty(pfd)) 1220 setty(); 1221 pstatus("%s is ready and printing", printer); 1222 } else if (RM != NULL) { 1223 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1224 resp = -1; 1225 pfd = getport(RM); 1226 if (pfd >= 0) { 1227 (void) sprintf(line, "\2%s\n", RP); 1228 n = strlen(line); 1229 if (write(pfd, line, n) == n && 1230 (resp = response()) == '\0') 1231 break; 1232 (void) close(pfd); 1233 } 1234 if (i == 1) { 1235 if (resp < 0) 1236 pstatus("waiting for %s to come up", RM); 1237 else { 1238 pstatus("waiting for queue to be enabled on %s", RM); 1239 i = 256; 1240 } 1241 } 1242 sleep(i); 1243 } 1244 pstatus("sending to %s", RM); 1245 remote = 1; 1246 } else { 1247 syslog(LOG_ERR, "%s: no line printer device or host name", 1248 printer); 1249 exit(1); 1250 } 1251 /* 1252 * Start up an output filter, if needed. 1253 */ 1254 if (!remote && OF) { 1255 int p[2]; 1256 char *cp; 1257 1258 pipe(p); 1259 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1260 dup2(p[0], 0); /* pipe is std in */ 1261 dup2(pfd, 1); /* printer is std out */ 1262 closelog(); 1263 for (i = 3; i < NOFILE; i++) 1264 (void) close(i); 1265 if ((cp = rindex(OF, '/')) == NULL) 1266 cp = OF; 1267 else 1268 cp++; 1269 execl(OF, cp, width, length, 0); 1270 openlog("lpd", LOG_PID, LOG_LPR); 1271 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1272 exit(1); 1273 } 1274 (void) close(p[0]); /* close input side */ 1275 ofd = p[1]; /* use pipe for output */ 1276 } else { 1277 ofd = pfd; 1278 ofilter = 0; 1279 } 1280} 1281 1282struct bauds { 1283 int baud; 1284 int speed; 1285} bauds[] = { 1286 50, B50, 1287 75, B75, 1288 110, B110, 1289 134, B134, 1290 150, B150, 1291 200, B200, 1292 300, B300, 1293 600, B600, 1294 1200, B1200, 1295 1800, B1800, 1296 2400, B2400, 1297 4800, B4800, 1298 9600, B9600, 1299 19200, EXTA, 1300 38400, EXTB, 1301 57600, B57600, 1302 115200, B115200, 1303 0, 0 1304}; 1305 1306/* 1307 * setup tty lines. 1308 */ 1309static void 1310setty() 1311{ 1312 struct sgttyb ttybuf; 1313 register struct bauds *bp; 1314 1315 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1316 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1317 exit(1); 1318 } 1319 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1320 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1321 exit(1); 1322 } 1323 if (BR > 0) { 1324 for (bp = bauds; bp->baud; bp++) 1325 if (BR == bp->baud) 1326 break; 1327 if (!bp->baud) { 1328 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1329 exit(1); 1330 } 1331 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1332 } 1333 ttybuf.sg_flags &= ~FC; 1334 ttybuf.sg_flags |= FS; 1335 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1336 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1337 exit(1); 1338 } 1339 if (XC) { 1340 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1341 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1342 exit(1); 1343 } 1344 } 1345 if (XS) { 1346 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1347 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1348 exit(1); 1349 } 1350 } 1351} 1352 1353#if __STDC__ 1354#include <stdarg.h> 1355#else 1356#include <varargs.h> 1357#endif 1358 1359void 1360#if __STDC__ 1361pstatus(const char *msg, ...) 1362#else 1363pstatus(msg, va_alist) 1364 char *msg; 1365 va_dcl 1366#endif 1367{ 1368 register int fd; 1369 char buf[BUFSIZ]; 1370 va_list ap; 1371#if __STDC__ 1372 va_start(ap, msg); 1373#else 1374 va_start(ap); 1375#endif 1376 1377 umask(0); 1378 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1379 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1380 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1381 exit(1); 1382 } 1383 ftruncate(fd, 0); 1384 (void)vsnprintf(buf, sizeof(buf), msg, ap); 1385 va_end(ap); 1386 strcat(buf, "\n"); 1387 (void) write(fd, buf, strlen(buf)); 1388 (void) close(fd); 1389} 1390