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 36 static const 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 42 /* 43 static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 44 */ 45 static const char rcsid[] = 46 "$FreeBSD$"; 47 #endif /* not lint */ 48 49 50 /* 51 * printjob -- print jobs in the queue. 52 * 53 * NOTE: the lock file is used to pass information to lpq and lprm. 54 * it does not need to be removed because file locks are dynamic. 55 */ 56 57 #include <sys/param.h> 58 #include <sys/wait.h> 59 #include <sys/stat.h> 60 #include <sys/types.h> 61 62 #include <pwd.h> 63 #include <unistd.h> 64 #include <signal.h> 65 #include <syslog.h> 66 #include <fcntl.h> 67 #include <dirent.h> 68 #include <errno.h> 69 #include <stdio.h> 70 #include <string.h> 71 #include <stdlib.h> 72 #include <sys/ioctl.h> 73 #include <termios.h> 74 #include <time.h> 75 #include "lp.h" 76 #include "lp.local.h" 77 #include "pathnames.h" 78 #include "extern.h" 79 80 #define DORETURN 0 /* absorb fork error */ 81 #define DOABORT 1 /* abort if dofork fails */ 82 83 /* 84 * Error tokens 85 */ 86 #define REPRINT -2 87 #define ERROR -1 88 #define OK 0 89 #define FATALERR 1 90 #define NOACCT 2 91 #define FILTERERR 3 92 #define ACCESS 4 93 94 static dev_t fdev; /* device of file pointed to by symlink */ 95 static ino_t fino; /* inode of file pointed to by symlink */ 96 static FILE *cfp; /* control file */ 97 static int child; /* id of any filters */ 98 static int job_dfcnt; /* count of datafiles in current user job */ 99 static int lfd; /* lock file descriptor */ 100 static int ofd; /* output filter file descriptor */ 101 static int ofilter; /* id of output filter, if any */ 102 static int tfd = -1; /* output filter temp file output */ 103 static int pfd; /* prstatic inter file descriptor */ 104 static int pid; /* pid of lpd process */ 105 static int prchild; /* id of pr process */ 106 static char title[80]; /* ``pr'' title */ 107 static char locale[80]; /* ``pr'' locale */ 108 109 static char class[32]; /* classification field */ 110 static char fromhost[MAXHOSTNAMELEN]; /* user's host machine */ 111 /* indentation size in static characters */ 112 static char indent[10] = "-i0"; 113 static char jobname[100]; /* job or file name */ 114 static char length[10] = "-l"; /* page length in lines */ 115 static char logname[32]; /* user's login name */ 116 static char pxlength[10] = "-y"; /* page length in pixels */ 117 static char pxwidth[10] = "-x"; /* page width in pixels */ 118 /* tempstderr is the filename used to catch stderr from exec-ing filters */ 119 static char tempstderr[] = "errs.XXXXXXX"; 120 static char width[10] = "-w"; /* page width in static characters */ 121 #define TFILENAME "fltXXXXXX" 122 static char tfile[] = TFILENAME; /* file name for filter output */ 123 124 static void abortpr __P((int)); 125 static void alarmhandler __P((int)); 126 static void banner __P((struct printer *pp, char *name1, char *name2)); 127 static int dofork __P((const struct printer *pp, int action)); 128 static int dropit __P((int)); 129 static void init __P((struct printer *pp)); 130 static void openpr __P((const struct printer *pp)); 131 static void opennet __P((const struct printer *pp)); 132 static void opentty __P((const struct printer *pp)); 133 static void openrem __P((const struct printer *pp)); 134 static int print __P((struct printer *pp, int format, char *file)); 135 static int printit __P((struct printer *pp, char *file)); 136 static void pstatus __P((const struct printer *, const char *, ...)); 137 static char response __P((const struct printer *pp)); 138 static void scan_out __P((struct printer *pp, int scfd, char *scsp, 139 int dlm)); 140 static char *scnline __P((int, char *, int)); 141 static int sendfile __P((struct printer *pp, int type, char *file, 142 int format)); 143 static int sendit __P((struct printer *pp, char *file)); 144 static void sendmail __P((struct printer *pp, char *user, int bombed)); 145 static void setty __P((const struct printer *pp)); 146 147 void 148 printjob(pp) 149 struct printer *pp; 150 { 151 struct stat stb; 152 register struct jobqueue *q, **qp; 153 struct jobqueue **queue; 154 register int i, nitems; 155 off_t pidoff; 156 int errcnt, jobcount, tempfd; 157 158 jobcount = 0; 159 init(pp); /* set up capabilities */ 160 (void) write(1, "", 1); /* ack that daemon is started */ 161 (void) close(2); /* set up log file */ 162 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) { 163 syslog(LOG_ERR, "%s: %m", pp->log_file); 164 (void) open(_PATH_DEVNULL, O_WRONLY); 165 } 166 setgid(getegid()); 167 pid = getpid(); /* for use with lprm */ 168 setpgrp(0, pid); 169 signal(SIGHUP, abortpr); 170 signal(SIGINT, abortpr); 171 signal(SIGQUIT, abortpr); 172 signal(SIGTERM, abortpr); 173 174 /* 175 * uses short form file names 176 */ 177 if (chdir(pp->spool_dir) < 0) { 178 syslog(LOG_ERR, "%s: %m", pp->spool_dir); 179 exit(1); 180 } 181 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS)) 182 exit(0); /* printing disabled */ 183 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 184 LOCK_FILE_MODE); 185 if (lfd < 0) { 186 if (errno == EWOULDBLOCK) /* active daemon present */ 187 exit(0); 188 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 189 exit(1); 190 } 191 /* turn off non-blocking mode (was turned on for lock effects only) */ 192 if (fcntl(lfd, F_SETFL, 0) < 0) { 193 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 194 exit(1); 195 } 196 ftruncate(lfd, 0); 197 /* 198 * write process id for others to know 199 */ 200 sprintf(line, "%u\n", pid); 201 pidoff = i = strlen(line); 202 if (write(lfd, line, i) != i) { 203 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file); 204 exit(1); 205 } 206 /* 207 * search the spool directory for work and sort by queue order. 208 */ 209 if ((nitems = getq(pp, &queue)) < 0) { 210 syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 211 pp->spool_dir); 212 exit(1); 213 } 214 if (nitems == 0) /* no work to do */ 215 exit(0); 216 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */ 217 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0) 218 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 219 pp->lock_file); 220 } 221 222 /* create a file which will be used to hold stderr from filters */ 223 if ((tempfd = mkstemp(tempstderr)) == -1) { 224 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 225 tempstderr); 226 exit(1); 227 } 228 if ((i = fchmod(tempfd, 0664)) == -1) { 229 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer, 230 tempstderr); 231 exit(1); 232 } 233 /* lpd doesn't need it to be open, it just needs it to exist */ 234 close(tempfd); 235 236 openpr(pp); /* open printer or remote */ 237 again: 238 /* 239 * we found something to do now do it -- 240 * write the name of the current control file into the lock file 241 * so the spool queue program can tell what we're working on 242 */ 243 for (qp = queue; nitems--; free((char *) q)) { 244 q = *qp++; 245 if (stat(q->job_cfname, &stb) < 0) 246 continue; 247 errcnt = 0; 248 restart: 249 (void) lseek(lfd, pidoff, 0); 250 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname); 251 i = strlen(line); 252 if (write(lfd, line, i) != i) 253 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 254 pp->lock_file); 255 if (!pp->remote) 256 i = printit(pp, q->job_cfname); 257 else 258 i = sendit(pp, q->job_cfname); 259 /* 260 * Check to see if we are supposed to stop printing or 261 * if we are to rebuild the queue. 262 */ 263 if (fstat(lfd, &stb) == 0) { 264 /* stop printing before starting next job? */ 265 if (stb.st_mode & LFM_PRINT_DIS) 266 goto done; 267 /* rebuild queue (after lpc topq) */ 268 if (stb.st_mode & LFM_RESET_QUE) { 269 for (free(q); nitems--; free(q)) 270 q = *qp++; 271 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) 272 < 0) 273 syslog(LOG_WARNING, "%s: %s: %m", 274 pp->printer, pp->lock_file); 275 break; 276 } 277 } 278 if (i == OK) /* all files of this job printed */ 279 jobcount++; 280 else if (i == REPRINT && ++errcnt < 5) { 281 /* try reprinting the job */ 282 syslog(LOG_INFO, "restarting %s", pp->printer); 283 if (ofilter > 0) { 284 kill(ofilter, SIGCONT); /* to be sure */ 285 (void) close(ofd); 286 while ((i = wait(NULL)) > 0 && i != ofilter) 287 ; 288 ofilter = 0; 289 } 290 (void) close(pfd); /* close printer */ 291 if (ftruncate(lfd, pidoff) < 0) 292 syslog(LOG_WARNING, "%s: %s: %m", 293 pp->printer, pp->lock_file); 294 openpr(pp); /* try to reopen printer */ 295 goto restart; 296 } else { 297 syslog(LOG_WARNING, "%s: job could not be %s (%s)", 298 pp->printer, 299 pp->remote ? "sent to remote host" : "printed", 300 q->job_cfname); 301 if (i == REPRINT) { 302 /* ensure we don't attempt this job again */ 303 (void) unlink(q->job_cfname); 304 q->job_cfname[0] = 'd'; 305 (void) unlink(q->job_cfname); 306 if (logname[0]) 307 sendmail(pp, logname, FATALERR); 308 } 309 } 310 } 311 free(queue); 312 /* 313 * search the spool directory for more work. 314 */ 315 if ((nitems = getq(pp, &queue)) < 0) { 316 syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 317 pp->spool_dir); 318 exit(1); 319 } 320 if (nitems == 0) { /* no more work to do */ 321 done: 322 if (jobcount > 0) { /* jobs actually printed */ 323 if (!pp->no_formfeed && !pp->tof) 324 (void) write(ofd, pp->form_feed, 325 strlen(pp->form_feed)); 326 if (pp->trailer != NULL) /* output trailer */ 327 (void) write(ofd, pp->trailer, 328 strlen(pp->trailer)); 329 } 330 (void) close(ofd); 331 (void) wait(NULL); 332 (void) unlink(tempstderr); 333 exit(0); 334 } 335 goto again; 336 } 337 338 char fonts[4][50]; /* fonts for troff */ 339 340 char ifonts[4][40] = { 341 _PATH_VFONTR, 342 _PATH_VFONTI, 343 _PATH_VFONTB, 344 _PATH_VFONTS, 345 }; 346 347 /* 348 * The remaining part is the reading of the control file (cf) 349 * and performing the various actions. 350 */ 351 static int 352 printit(pp, file) 353 struct printer *pp; 354 char *file; 355 { 356 register int i; 357 char *cp; 358 int bombed, didignorehdr; 359 360 bombed = OK; 361 didignorehdr = 0; 362 /* 363 * open control file; ignore if no longer there. 364 */ 365 if ((cfp = fopen(file, "r")) == NULL) { 366 syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 367 return(OK); 368 } 369 /* 370 * Reset troff fonts. 371 */ 372 for (i = 0; i < 4; i++) 373 strcpy(fonts[i], ifonts[i]); 374 sprintf(&width[2], "%ld", pp->page_width); 375 strcpy(indent+2, "0"); 376 377 /* initialize job-specific count of datafiles processed */ 378 job_dfcnt = 0; 379 380 /* 381 * read the control file for work to do 382 * 383 * file format -- first character in the line is a command 384 * rest of the line is the argument. 385 * valid commands are: 386 * 387 * S -- "stat info" for symbolic link protection 388 * J -- "job name" on banner page 389 * C -- "class name" on banner page 390 * L -- "literal" user's name to print on banner 391 * T -- "title" for pr 392 * H -- "host name" of machine where lpr was done 393 * P -- "person" user's login name 394 * I -- "indent" amount to indent output 395 * R -- laser dpi "resolution" 396 * f -- "file name" name of text file to print 397 * l -- "file name" text file with control chars 398 * p -- "file name" text file to print with pr(1) 399 * t -- "file name" troff(1) file to print 400 * n -- "file name" ditroff(1) file to print 401 * d -- "file name" dvi file to print 402 * g -- "file name" plot(1G) file to print 403 * v -- "file name" plain raster file to print 404 * c -- "file name" cifplot file to print 405 * 1 -- "R font file" for troff 406 * 2 -- "I font file" for troff 407 * 3 -- "B font file" for troff 408 * 4 -- "S font file" for troff 409 * N -- "name" of file (used by lpq) 410 * U -- "unlink" name of file to remove 411 * (after we print it. (Pass 2 only)). 412 * M -- "mail" to user when done printing 413 * Z -- "locale" for pr 414 * 415 * getline reads a line and expands tabs to blanks 416 */ 417 418 /* pass 1 */ 419 420 while (getline(cfp)) 421 switch (line[0]) { 422 case 'H': 423 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 424 fromhost[sizeof(fromhost) - 1] = '\0'; 425 if (class[0] == '\0') { 426 strncpy(class, line+1, sizeof(class) - 1); 427 class[sizeof(class) - 1] = '\0'; 428 } 429 continue; 430 431 case 'P': 432 strncpy(logname, line+1, sizeof(logname) - 1); 433 logname[sizeof(logname) - 1] = '\0'; 434 if (pp->restricted) { /* restricted */ 435 if (getpwnam(logname) == NULL) { 436 bombed = NOACCT; 437 sendmail(pp, line+1, bombed); 438 goto pass2; 439 } 440 } 441 continue; 442 443 case 'S': 444 cp = line+1; 445 i = 0; 446 while (*cp >= '0' && *cp <= '9') 447 i = i * 10 + (*cp++ - '0'); 448 fdev = i; 449 cp++; 450 i = 0; 451 while (*cp >= '0' && *cp <= '9') 452 i = i * 10 + (*cp++ - '0'); 453 fino = i; 454 continue; 455 456 case 'J': 457 if (line[1] != '\0') { 458 strncpy(jobname, line+1, sizeof(jobname) - 1); 459 jobname[sizeof(jobname) - 1] = '\0'; 460 } else 461 strcpy(jobname, " "); 462 continue; 463 464 case 'C': 465 if (line[1] != '\0') 466 strncpy(class, line+1, sizeof(class) - 1); 467 else if (class[0] == '\0') 468 gethostname(class, sizeof(class)); 469 class[sizeof(class) - 1] = '\0'; 470 continue; 471 472 case 'T': /* header title for pr */ 473 strncpy(title, line+1, sizeof(title) - 1); 474 title[sizeof(title) - 1] = '\0'; 475 continue; 476 477 case 'L': /* identification line */ 478 if (!pp->no_header && !pp->header_last) 479 banner(pp, line+1, jobname); 480 continue; 481 482 case '1': /* troff fonts */ 483 case '2': 484 case '3': 485 case '4': 486 if (line[1] != '\0') { 487 strncpy(fonts[line[0]-'1'], line+1, 488 50-1); 489 fonts[line[0]-'1'][50-1] = '\0'; 490 } 491 continue; 492 493 case 'W': /* page width */ 494 strncpy(width+2, line+1, sizeof(width) - 3); 495 width[2+sizeof(width) - 3] = '\0'; 496 continue; 497 498 case 'I': /* indent amount */ 499 strncpy(indent+2, line+1, sizeof(indent) - 3); 500 indent[2+sizeof(indent) - 3] = '\0'; 501 continue; 502 503 case 'Z': /* locale for pr */ 504 strncpy(locale, line+1, sizeof(locale) - 1); 505 locale[sizeof(locale) - 1] = '\0'; 506 continue; 507 508 default: /* some file to print */ 509 /* only lowercase cmd-codes include a file-to-print */ 510 if ((line[0] < 'a') || (line[0] > 'z')) { 511 /* ignore any other lines */ 512 if (lflag <= 1) 513 continue; 514 if (!didignorehdr) { 515 syslog(LOG_INFO, "%s: in %s :", 516 pp->printer, file); 517 didignorehdr = 1; 518 } 519 syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 520 pp->printer, line[0], &line[1]); 521 continue; 522 } 523 i = print(pp, line[0], line+1); 524 switch (i) { 525 case ERROR: 526 if (bombed == OK) 527 bombed = FATALERR; 528 break; 529 case REPRINT: 530 (void) fclose(cfp); 531 return(REPRINT); 532 case FILTERERR: 533 case ACCESS: 534 bombed = i; 535 sendmail(pp, logname, bombed); 536 } 537 title[0] = '\0'; 538 continue; 539 540 case 'N': 541 case 'U': 542 case 'M': 543 case 'R': 544 continue; 545 } 546 547 /* pass 2 */ 548 549 pass2: 550 fseek(cfp, 0L, 0); 551 while (getline(cfp)) 552 switch (line[0]) { 553 case 'L': /* identification line */ 554 if (!pp->no_header && pp->header_last) 555 banner(pp, line+1, jobname); 556 continue; 557 558 case 'M': 559 if (bombed < NOACCT) /* already sent if >= NOACCT */ 560 sendmail(pp, line+1, bombed); 561 continue; 562 563 case 'U': 564 if (strchr(line+1, '/')) 565 continue; 566 (void) unlink(line+1); 567 } 568 /* 569 * clean-up in case another control file exists 570 */ 571 (void) fclose(cfp); 572 (void) unlink(file); 573 return(bombed == OK ? OK : ERROR); 574 } 575 576 /* 577 * Print a file. 578 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 579 * Return -1 if a non-recoverable error occured, 580 * 2 if the filter detected some errors (but printed the job anyway), 581 * 1 if we should try to reprint this job and 582 * 0 if all is well. 583 * Note: all filters take stdin as the file, stdout as the printer, 584 * stderr as the log file, and must not ignore SIGINT. 585 */ 586 static int 587 print(pp, format, file) 588 struct printer *pp; 589 int format; 590 char *file; 591 { 592 register int n, i; 593 register char *prog; 594 int fi, fo; 595 FILE *fp; 596 char *av[15], buf[BUFSIZ]; 597 int pid, p[2], stopped; 598 union wait status; 599 struct stat stb; 600 601 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 602 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 603 pp->printer, file, format); 604 return(ERROR); 605 } 606 /* 607 * Check to see if data file is a symbolic link. If so, it should 608 * still point to the same file or someone is trying to print 609 * something he shouldn't. 610 */ 611 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 612 (stb.st_dev != fdev || stb.st_ino != fino)) 613 return(ACCESS); 614 615 job_dfcnt++; /* increment datafile counter for this job */ 616 stopped = 0; /* output filter is not stopped */ 617 618 /* everything seems OK, start it up */ 619 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 620 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 621 pp->tof = 1; 622 } 623 if (pp->filters[LPF_INPUT] == NULL 624 && (format == 'f' || format == 'l')) { 625 pp->tof = 0; 626 while ((n = read(fi, buf, BUFSIZ)) > 0) 627 if (write(ofd, buf, n) != n) { 628 (void) close(fi); 629 return(REPRINT); 630 } 631 (void) close(fi); 632 return(OK); 633 } 634 switch (format) { 635 case 'p': /* print file using 'pr' */ 636 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 637 prog = _PATH_PR; 638 i = 0; 639 av[i++] = "pr"; 640 av[i++] = width; 641 av[i++] = length; 642 av[i++] = "-h"; 643 av[i++] = *title ? title : " "; 644 av[i++] = "-L"; 645 av[i++] = *locale ? locale : "C"; 646 av[i++] = "-F"; 647 av[i] = 0; 648 fo = ofd; 649 goto start; 650 } 651 pipe(p); 652 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 653 dup2(fi, 0); /* file is stdin */ 654 dup2(p[1], 1); /* pipe is stdout */ 655 closelog(); 656 closeallfds(3); 657 execl(_PATH_PR, "pr", width, length, 658 "-h", *title ? title : " ", 659 "-L", *locale ? locale : "C", 660 "-F", 0); 661 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 662 exit(2); 663 } 664 (void) close(p[1]); /* close output side */ 665 (void) close(fi); 666 if (prchild < 0) { 667 prchild = 0; 668 (void) close(p[0]); 669 return(ERROR); 670 } 671 fi = p[0]; /* use pipe for input */ 672 case 'f': /* print plain text file */ 673 prog = pp->filters[LPF_INPUT]; 674 av[1] = width; 675 av[2] = length; 676 av[3] = indent; 677 n = 4; 678 break; 679 case 'l': /* like 'f' but pass control characters */ 680 prog = pp->filters[LPF_INPUT]; 681 av[1] = "-c"; 682 av[2] = width; 683 av[3] = length; 684 av[4] = indent; 685 n = 5; 686 break; 687 case 'r': /* print a fortran text file */ 688 prog = pp->filters[LPF_FORTRAN]; 689 av[1] = width; 690 av[2] = length; 691 n = 3; 692 break; 693 case 't': /* print troff output */ 694 case 'n': /* print ditroff output */ 695 case 'd': /* print tex output */ 696 (void) unlink(".railmag"); 697 if ((fo = creat(".railmag", FILMOD)) < 0) { 698 syslog(LOG_ERR, "%s: cannot create .railmag", 699 pp->printer); 700 (void) unlink(".railmag"); 701 } else { 702 for (n = 0; n < 4; n++) { 703 if (fonts[n][0] != '/') 704 (void) write(fo, _PATH_VFONT, 705 sizeof(_PATH_VFONT) - 1); 706 (void) write(fo, fonts[n], strlen(fonts[n])); 707 (void) write(fo, "\n", 1); 708 } 709 (void) close(fo); 710 } 711 prog = (format == 't') ? pp->filters[LPF_TROFF] 712 : ((format == 'n') ? pp->filters[LPF_DITROFF] 713 : pp->filters[LPF_DVI]); 714 av[1] = pxwidth; 715 av[2] = pxlength; 716 n = 3; 717 break; 718 case 'c': /* print cifplot output */ 719 prog = pp->filters[LPF_CIFPLOT]; 720 av[1] = pxwidth; 721 av[2] = pxlength; 722 n = 3; 723 break; 724 case 'g': /* print plot(1G) output */ 725 prog = pp->filters[LPF_GRAPH]; 726 av[1] = pxwidth; 727 av[2] = pxlength; 728 n = 3; 729 break; 730 case 'v': /* print raster output */ 731 prog = pp->filters[LPF_RASTER]; 732 av[1] = pxwidth; 733 av[2] = pxlength; 734 n = 3; 735 break; 736 default: 737 (void) close(fi); 738 syslog(LOG_ERR, "%s: illegal format character '%c'", 739 pp->printer, format); 740 return(ERROR); 741 } 742 if (prog == NULL) { 743 (void) close(fi); 744 syslog(LOG_ERR, 745 "%s: no filter found in printcap for format character '%c'", 746 pp->printer, format); 747 return(ERROR); 748 } 749 if ((av[0] = strrchr(prog, '/')) != NULL) 750 av[0]++; 751 else 752 av[0] = prog; 753 av[n++] = "-n"; 754 av[n++] = logname; 755 av[n++] = "-h"; 756 av[n++] = fromhost; 757 av[n++] = pp->acct_file; 758 av[n] = 0; 759 fo = pfd; 760 if (ofilter > 0) { /* stop output filter */ 761 write(ofd, "\031\1", 2); 762 while ((pid = 763 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 764 ; 765 if (status.w_stopval != WSTOPPED) { 766 (void) close(fi); 767 syslog(LOG_WARNING, 768 "%s: output filter died " 769 "(retcode=%d termsig=%d)", 770 pp->printer, status.w_retcode, 771 status.w_termsig); 772 return(REPRINT); 773 } 774 stopped++; 775 } 776 start: 777 if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 778 dup2(fi, 0); 779 dup2(fo, 1); 780 /* setup stderr for the filter (child process) 781 * so it goes to our temporary errors file */ 782 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 783 if (n >= 0) 784 dup2(n, 2); 785 closelog(); 786 closeallfds(3); 787 execv(prog, av); 788 syslog(LOG_ERR, "cannot execv %s", prog); 789 exit(2); 790 } 791 (void) close(fi); 792 if (child < 0) 793 status.w_retcode = 100; 794 else 795 while ((pid = wait((int *)&status)) > 0 && pid != child) 796 ; 797 child = 0; 798 prchild = 0; 799 if (stopped) { /* restart output filter */ 800 if (kill(ofilter, SIGCONT) < 0) { 801 syslog(LOG_ERR, "cannot restart output filter"); 802 exit(1); 803 } 804 } 805 pp->tof = 0; 806 807 /* Copy the filter's output to "lf" logfile */ 808 if ((fp = fopen(tempstderr, "r"))) { 809 while (fgets(buf, sizeof(buf), fp)) 810 fputs(buf, stderr); 811 fclose(fp); 812 } 813 814 if (!WIFEXITED(status)) { 815 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 816 pp->printer, format, status.w_termsig); 817 return(ERROR); 818 } 819 switch (status.w_retcode) { 820 case 0: 821 pp->tof = 1; 822 return(OK); 823 case 1: 824 return(REPRINT); 825 case 2: 826 return(ERROR); 827 default: 828 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 829 pp->printer, format, status.w_retcode); 830 return(FILTERERR); 831 } 832 } 833 834 /* 835 * Send the daemon control file (cf) and any data files. 836 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 837 * 0 if all is well. 838 */ 839 static int 840 sendit(pp, file) 841 struct printer *pp; 842 char *file; 843 { 844 register int i, err = OK; 845 char *cp, last[BUFSIZ]; 846 847 /* 848 * open control file 849 */ 850 if ((cfp = fopen(file, "r")) == NULL) 851 return(OK); 852 853 /* initialize job-specific count of datafiles processed */ 854 job_dfcnt = 0; 855 856 /* 857 * read the control file for work to do 858 * 859 * file format -- first character in the line is a command 860 * rest of the line is the argument. 861 * commands of interest are: 862 * 863 * a-z -- "file name" name of file to print 864 * U -- "unlink" name of file to remove 865 * (after we print it. (Pass 2 only)). 866 */ 867 868 /* 869 * pass 1 870 */ 871 while (getline(cfp)) { 872 again: 873 if (line[0] == 'S') { 874 cp = line+1; 875 i = 0; 876 while (*cp >= '0' && *cp <= '9') 877 i = i * 10 + (*cp++ - '0'); 878 fdev = i; 879 cp++; 880 i = 0; 881 while (*cp >= '0' && *cp <= '9') 882 i = i * 10 + (*cp++ - '0'); 883 fino = i; 884 } else if (line[0] == 'H') { 885 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 886 fromhost[sizeof(fromhost) - 1] = '\0'; 887 if (class[0] == '\0') { 888 strncpy(class, line+1, sizeof(class) - 1); 889 class[sizeof(class) - 1] = '\0'; 890 } 891 } else if (line[0] == 'P') { 892 strncpy(logname, line+1, sizeof(logname) - 1); 893 logname[sizeof(logname) - 1] = '\0'; 894 if (pp->restricted) { /* restricted */ 895 if (getpwnam(logname) == NULL) { 896 sendmail(pp, line+1, NOACCT); 897 err = ERROR; 898 break; 899 } 900 } 901 } else if (line[0] == 'I') { 902 strncpy(indent+2, line+1, sizeof(indent) - 3); 903 indent[2 + sizeof(indent) - 3] = '\0'; 904 } else if (line[0] >= 'a' && line[0] <= 'z') { 905 strcpy(last, line); 906 while ((i = getline(cfp)) != 0) 907 if (strcmp(last, line)) 908 break; 909 switch (sendfile(pp, '\3', last+1, *last)) { 910 case OK: 911 if (i) 912 goto again; 913 break; 914 case REPRINT: 915 (void) fclose(cfp); 916 return(REPRINT); 917 case ACCESS: 918 sendmail(pp, logname, ACCESS); 919 case ERROR: 920 err = ERROR; 921 } 922 break; 923 } 924 } 925 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 926 (void) fclose(cfp); 927 return(REPRINT); 928 } 929 /* 930 * pass 2 931 */ 932 fseek(cfp, 0L, 0); 933 while (getline(cfp)) 934 if (line[0] == 'U' && !strchr(line+1, '/')) 935 (void) unlink(line+1); 936 /* 937 * clean-up in case another control file exists 938 */ 939 (void) fclose(cfp); 940 (void) unlink(file); 941 return(err); 942 } 943 944 /* 945 * Send a data file to the remote machine and spool it. 946 * Return positive if we should try resending. 947 */ 948 static int 949 sendfile(pp, type, file, format) 950 struct printer *pp; 951 int type; 952 char *file; 953 char format; 954 { 955 register int f, i, amt; 956 struct stat stb; 957 FILE *fp; 958 char buf[BUFSIZ]; 959 int sizerr, resp, closedpr; 960 961 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 962 return(ERROR); 963 /* 964 * Check to see if data file is a symbolic link. If so, it should 965 * still point to the same file or someone is trying to print something 966 * he shouldn't. 967 */ 968 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 969 (stb.st_dev != fdev || stb.st_ino != fino)) 970 return(ACCESS); 971 972 job_dfcnt++; /* increment datafile counter for this job */ 973 974 /* everything seems OK, start it up */ 975 sizerr = 0; 976 closedpr = 0; 977 if (type == '\3') { 978 if (pp->filters[LPF_INPUT]) { 979 /* 980 * We're sending something with an ifilter, we have to 981 * run the ifilter and store the output as a 982 * temporary file (tfile)... the protocol requires us 983 * to send the file size 984 */ 985 char *av[15]; 986 int n; 987 int ifilter; 988 union wait status; /* XXX */ 989 990 strcpy(tfile,TFILENAME); 991 if ((tfd = mkstemp(tfile)) == -1) { 992 syslog(LOG_ERR, "mkstemp: %m"); 993 return(ERROR); 994 } 995 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 996 av[0] = pp->filters[LPF_INPUT]; 997 else 998 av[0]++; 999 if (format == 'l') 1000 av[n=1] = "-c"; 1001 else 1002 n = 0; 1003 av[++n] = width; 1004 av[++n] = length; 1005 av[++n] = indent; 1006 av[++n] = "-n"; 1007 av[++n] = logname; 1008 av[++n] = "-h"; 1009 av[++n] = fromhost; 1010 av[++n] = pp->acct_file; 1011 av[++n] = 0; 1012 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 1013 dup2(f, 0); 1014 dup2(tfd, 1); 1015 /* setup stderr for the filter (child process) 1016 * so it goes to our temporary errors file */ 1017 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1018 if (n >= 0) 1019 dup2(n, 2); 1020 closelog(); 1021 closeallfds(3); 1022 execv(pp->filters[LPF_INPUT], av); 1023 syslog(LOG_ERR, "cannot execv %s", 1024 pp->filters[LPF_INPUT]); 1025 exit(2); 1026 } 1027 (void) close(f); 1028 if (ifilter < 0) 1029 status.w_retcode = 100; 1030 else 1031 while ((pid = wait((int *)&status)) > 0 && 1032 pid != ifilter) 1033 ; 1034 /* Copy the filter's output to "lf" logfile */ 1035 if ((fp = fopen(tempstderr, "r"))) { 1036 while (fgets(buf, sizeof(buf), fp)) 1037 fputs(buf, stderr); 1038 fclose(fp); 1039 } 1040 /* process the return-code from the filter */ 1041 switch (status.w_retcode) { 1042 case 0: 1043 break; 1044 case 1: 1045 unlink(tfile); 1046 return(REPRINT); 1047 case 2: 1048 unlink(tfile); 1049 return(ERROR); 1050 default: 1051 syslog(LOG_WARNING, "%s: filter '%c' exited" 1052 " (retcode=%d)", 1053 pp->printer, format, status.w_retcode); 1054 unlink(tfile); 1055 return(FILTERERR); 1056 } 1057 if (fstat(tfd, &stb) < 0) /* the size of tfile */ 1058 return(ERROR); 1059 f = tfd; 1060 lseek(f,0,SEEK_SET); 1061 } else if (ofilter) { 1062 /* 1063 * We're sending something with an ofilter, we have to 1064 * store the output as a temporary file (tfile)... the 1065 * protocol requires us to send the file size 1066 */ 1067 int i; 1068 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1069 amt = BUFSIZ; 1070 if (i + amt > stb.st_size) 1071 amt = stb.st_size - i; 1072 if (sizerr == 0 && read(f, buf, amt) != amt) { 1073 sizerr = 1; 1074 break; 1075 } 1076 if (write(ofd, buf, amt) != amt) { 1077 (void) close(f); 1078 return(REPRINT); 1079 } 1080 } 1081 close(ofd); 1082 close(f); 1083 while ((i = wait(NULL)) > 0 && i != ofilter) 1084 ; 1085 ofilter = 0; 1086 if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 1087 openpr(pp); 1088 return(ERROR); 1089 } 1090 f = tfd; 1091 lseek(f,0,SEEK_SET); 1092 closedpr = 1; 1093 } 1094 } 1095 1096 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1097 amt = strlen(buf); 1098 for (i = 0; ; i++) { 1099 if (write(pfd, buf, amt) != amt || 1100 (resp = response(pp)) < 0 || resp == '\1') { 1101 (void) close(f); 1102 if (tfd != -1 && type == '\3') { 1103 tfd = -1; 1104 unlink(tfile); 1105 if (closedpr) 1106 openpr(pp); 1107 } 1108 return(REPRINT); 1109 } else if (resp == '\0') 1110 break; 1111 if (i == 0) 1112 pstatus(pp, 1113 "no space on remote; waiting for queue to drain"); 1114 if (i == 10) 1115 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1116 pp->printer, pp->remote_host); 1117 sleep(5 * 60); 1118 } 1119 if (i) 1120 pstatus(pp, "sending to %s", pp->remote_host); 1121 if (type == '\3') 1122 trstat_init(pp, file, job_dfcnt); 1123 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1124 amt = BUFSIZ; 1125 if (i + amt > stb.st_size) 1126 amt = stb.st_size - i; 1127 if (sizerr == 0 && read(f, buf, amt) != amt) 1128 sizerr = 1; 1129 if (write(pfd, buf, amt) != amt) { 1130 (void) close(f); 1131 if (tfd != -1 && type == '\3') { 1132 tfd = -1; 1133 unlink(tfile); 1134 if (closedpr) 1135 openpr(pp); 1136 } 1137 return(REPRINT); 1138 } 1139 } 1140 1141 (void) close(f); 1142 if (tfd != -1 && type == '\3') { 1143 tfd = -1; 1144 unlink(tfile); 1145 } 1146 if (sizerr) { 1147 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1148 /* tell recvjob to ignore this file */ 1149 (void) write(pfd, "\1", 1); 1150 if (closedpr) 1151 openpr(pp); 1152 return(ERROR); 1153 } 1154 if (write(pfd, "", 1) != 1 || response(pp)) { 1155 if (closedpr) 1156 openpr(pp); 1157 return(REPRINT); 1158 } 1159 if (closedpr) 1160 openpr(pp); 1161 if (type == '\3') 1162 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1163 pp->remote_host, fromhost); 1164 return(OK); 1165 } 1166 1167 /* 1168 * Check to make sure there have been no errors and that both programs 1169 * are in sync with eachother. 1170 * Return non-zero if the connection was lost. 1171 */ 1172 static char 1173 response(pp) 1174 const struct printer *pp; 1175 { 1176 char resp; 1177 1178 if (read(pfd, &resp, 1) != 1) { 1179 syslog(LOG_INFO, "%s: lost connection", pp->printer); 1180 return(-1); 1181 } 1182 return(resp); 1183 } 1184 1185 /* 1186 * Banner printing stuff 1187 */ 1188 static void 1189 banner(pp, name1, name2) 1190 struct printer *pp; 1191 char *name1, *name2; 1192 { 1193 time_t tvec; 1194 1195 time(&tvec); 1196 if (!pp->no_formfeed && !pp->tof) 1197 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1198 if (pp->short_banner) { /* short banner only */ 1199 if (class[0]) { 1200 (void) write(ofd, class, strlen(class)); 1201 (void) write(ofd, ":", 1); 1202 } 1203 (void) write(ofd, name1, strlen(name1)); 1204 (void) write(ofd, " Job: ", 7); 1205 (void) write(ofd, name2, strlen(name2)); 1206 (void) write(ofd, " Date: ", 8); 1207 (void) write(ofd, ctime(&tvec), 24); 1208 (void) write(ofd, "\n", 1); 1209 } else { /* normal banner */ 1210 (void) write(ofd, "\n\n\n", 3); 1211 scan_out(pp, ofd, name1, '\0'); 1212 (void) write(ofd, "\n\n", 2); 1213 scan_out(pp, ofd, name2, '\0'); 1214 if (class[0]) { 1215 (void) write(ofd,"\n\n\n",3); 1216 scan_out(pp, ofd, class, '\0'); 1217 } 1218 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1219 (void) write(ofd, name2, strlen(name2)); 1220 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1221 (void) write(ofd, ctime(&tvec), 24); 1222 (void) write(ofd, "\n", 1); 1223 } 1224 if (!pp->no_formfeed) 1225 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1226 pp->tof = 1; 1227 } 1228 1229 static char * 1230 scnline(key, p, c) 1231 register int key; 1232 register char *p; 1233 int c; 1234 { 1235 register int scnwidth; 1236 1237 for (scnwidth = WIDTH; --scnwidth;) { 1238 key <<= 1; 1239 *p++ = key & 0200 ? c : BACKGND; 1240 } 1241 return (p); 1242 } 1243 1244 #define TRC(q) (((q)-' ')&0177) 1245 1246 static void 1247 scan_out(pp, scfd, scsp, dlm) 1248 struct printer *pp; 1249 int scfd, dlm; 1250 char *scsp; 1251 { 1252 register char *strp; 1253 register int nchrs, j; 1254 char outbuf[LINELEN+1], *sp, c, cc; 1255 int d, scnhgt; 1256 1257 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1258 strp = &outbuf[0]; 1259 sp = scsp; 1260 for (nchrs = 0; ; ) { 1261 d = dropit(c = TRC(cc = *sp++)); 1262 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1263 for (j = WIDTH; --j;) 1264 *strp++ = BACKGND; 1265 else 1266 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1267 if (*sp == dlm || *sp == '\0' || 1268 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1269 break; 1270 *strp++ = BACKGND; 1271 *strp++ = BACKGND; 1272 } 1273 while (*--strp == BACKGND && strp >= outbuf) 1274 ; 1275 strp++; 1276 *strp++ = '\n'; 1277 (void) write(scfd, outbuf, strp-outbuf); 1278 } 1279 } 1280 1281 static int 1282 dropit(c) 1283 int c; 1284 { 1285 switch(c) { 1286 1287 case TRC('_'): 1288 case TRC(';'): 1289 case TRC(','): 1290 case TRC('g'): 1291 case TRC('j'): 1292 case TRC('p'): 1293 case TRC('q'): 1294 case TRC('y'): 1295 return (DROP); 1296 1297 default: 1298 return (0); 1299 } 1300 } 1301 1302 /* 1303 * sendmail --- 1304 * tell people about job completion 1305 */ 1306 static void 1307 sendmail(pp, user, bombed) 1308 struct printer *pp; 1309 char *user; 1310 int bombed; 1311 { 1312 register int i; 1313 int p[2], s; 1314 register char *cp; 1315 struct stat stb; 1316 FILE *fp; 1317 1318 pipe(p); 1319 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1320 dup2(p[0], 0); 1321 closelog(); 1322 closeallfds(3); 1323 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1324 cp++; 1325 else 1326 cp = _PATH_SENDMAIL; 1327 execl(_PATH_SENDMAIL, cp, "-t", 0); 1328 _exit(0); 1329 } else if (s > 0) { /* parent */ 1330 dup2(p[1], 1); 1331 printf("To: %s@%s\n", user, fromhost); 1332 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1333 *jobname ? jobname : "<unknown>"); 1334 printf("Reply-To: root@%s\n\n", host); 1335 printf("Your printer job "); 1336 if (*jobname) 1337 printf("(%s) ", jobname); 1338 1339 cp = "XXX compiler confusion"; /* XXX shut GCC up */ 1340 switch (bombed) { 1341 case OK: 1342 printf("\ncompleted successfully\n"); 1343 cp = "OK"; 1344 break; 1345 default: 1346 case FATALERR: 1347 printf("\ncould not be printed\n"); 1348 cp = "FATALERR"; 1349 break; 1350 case NOACCT: 1351 printf("\ncould not be printed without an account on %s\n", host); 1352 cp = "NOACCT"; 1353 break; 1354 case FILTERERR: 1355 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1356 || (fp = fopen(tempstderr, "r")) == NULL) { 1357 printf("\nhad some errors and may not have printed\n"); 1358 break; 1359 } 1360 printf("\nhad the following errors and may not have printed:\n"); 1361 while ((i = getc(fp)) != EOF) 1362 putchar(i); 1363 (void) fclose(fp); 1364 cp = "FILTERERR"; 1365 break; 1366 case ACCESS: 1367 printf("\nwas not printed because it was not linked to the original file\n"); 1368 cp = "ACCESS"; 1369 } 1370 fflush(stdout); 1371 (void) close(1); 1372 } else { 1373 syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 1374 return; 1375 } 1376 (void) close(p[0]); 1377 (void) close(p[1]); 1378 wait(NULL); 1379 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1380 user, *jobname ? jobname : "<unknown>", pp->printer, cp); 1381 } 1382 1383 /* 1384 * dofork - fork with retries on failure 1385 */ 1386 static int 1387 dofork(pp, action) 1388 const struct printer *pp; 1389 int action; 1390 { 1391 register int i, pid; 1392 struct passwd *pwd; 1393 1394 for (i = 0; i < 20; i++) { 1395 if ((pid = fork()) < 0) { 1396 sleep((unsigned)(i*i)); 1397 continue; 1398 } 1399 /* 1400 * Child should run as daemon instead of root 1401 */ 1402 if (pid == 0) { 1403 if ((pwd = getpwuid(pp->daemon_user)) == NULL) { 1404 syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", 1405 pp->daemon_user); 1406 break; 1407 } 1408 initgroups(pwd->pw_name, pwd->pw_gid); 1409 setgid(pwd->pw_gid); 1410 setuid(pp->daemon_user); 1411 } 1412 return(pid); 1413 } 1414 syslog(LOG_ERR, "can't fork"); 1415 1416 switch (action) { 1417 case DORETURN: 1418 return (-1); 1419 default: 1420 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1421 /*FALL THRU*/ 1422 case DOABORT: 1423 exit(1); 1424 } 1425 /*NOTREACHED*/ 1426 } 1427 1428 /* 1429 * Kill child processes to abort current job. 1430 */ 1431 static void 1432 abortpr(signo) 1433 int signo; 1434 { 1435 1436 (void) unlink(tempstderr); 1437 kill(0, SIGINT); 1438 if (ofilter > 0) 1439 kill(ofilter, SIGCONT); 1440 while (wait(NULL) > 0) 1441 ; 1442 if (ofilter > 0 && tfd != -1) 1443 unlink(tfile); 1444 exit(0); 1445 } 1446 1447 static void 1448 init(pp) 1449 struct printer *pp; 1450 { 1451 char *s; 1452 1453 sprintf(&width[2], "%ld", pp->page_width); 1454 sprintf(&length[2], "%ld", pp->page_length); 1455 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1456 sprintf(&pxlength[2], "%ld", pp->page_plength); 1457 if ((s = checkremote(pp)) != 0) { 1458 syslog(LOG_WARNING, "%s", s); 1459 free(s); 1460 } 1461 } 1462 1463 void 1464 startprinting(printer) 1465 const char *printer; 1466 { 1467 struct printer myprinter, *pp = &myprinter; 1468 int status; 1469 1470 init_printer(pp); 1471 status = getprintcap(printer, pp); 1472 switch(status) { 1473 case PCAPERR_OSERR: 1474 syslog(LOG_ERR, "can't open printer description file: %m"); 1475 exit(1); 1476 case PCAPERR_NOTFOUND: 1477 syslog(LOG_ERR, "unknown printer: %s", printer); 1478 exit(1); 1479 case PCAPERR_TCLOOP: 1480 fatal(pp, "potential reference loop detected in printcap file"); 1481 default: 1482 break; 1483 } 1484 printjob(pp); 1485 } 1486 1487 /* 1488 * Acquire line printer or remote connection. 1489 */ 1490 static void 1491 openpr(pp) 1492 const struct printer *pp; 1493 { 1494 int p[2]; 1495 char *cp; 1496 1497 if (pp->remote) { 1498 openrem(pp); 1499 } else if (*pp->lp) { 1500 if ((cp = strchr(pp->lp, '@')) != NULL) 1501 opennet(pp); 1502 else 1503 opentty(pp); 1504 } else { 1505 syslog(LOG_ERR, "%s: no line printer device or host name", 1506 pp->printer); 1507 exit(1); 1508 } 1509 1510 /* 1511 * Start up an output filter, if needed. 1512 */ 1513 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1514 pipe(p); 1515 if (pp->remote) { 1516 strcpy(tfile, TFILENAME); 1517 tfd = mkstemp(tfile); 1518 } 1519 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1520 dup2(p[0], 0); /* pipe is std in */ 1521 /* tfile/printer is stdout */ 1522 dup2(pp->remote ? tfd : pfd, 1); 1523 closelog(); 1524 closeallfds(3); 1525 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1526 cp = pp->filters[LPF_OUTPUT]; 1527 else 1528 cp++; 1529 execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); 1530 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1531 pp->filters[LPF_OUTPUT]); 1532 exit(1); 1533 } 1534 (void) close(p[0]); /* close input side */ 1535 ofd = p[1]; /* use pipe for output */ 1536 } else { 1537 ofd = pfd; 1538 ofilter = 0; 1539 } 1540 } 1541 1542 /* 1543 * Printer connected directly to the network 1544 * or to a terminal server on the net 1545 */ 1546 static void 1547 opennet(pp) 1548 const struct printer *pp; 1549 { 1550 register int i; 1551 int resp; 1552 u_long port; 1553 char *ep; 1554 void (*savealrm)(int); 1555 1556 port = strtoul(pp->lp, &ep, 0); 1557 if (*ep != '@' || port > 65535) { 1558 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1559 pp->lp); 1560 exit(1); 1561 } 1562 ep++; 1563 1564 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1565 resp = -1; 1566 savealrm = signal(SIGALRM, alarmhandler); 1567 alarm(pp->conn_timeout); 1568 pfd = getport(pp, ep, port); 1569 alarm(0); 1570 (void)signal(SIGALRM, savealrm); 1571 if (pfd < 0 && errno == ECONNREFUSED) 1572 resp = 1; 1573 else if (pfd >= 0) { 1574 /* 1575 * need to delay a bit for rs232 lines 1576 * to stabilize in case printer is 1577 * connected via a terminal server 1578 */ 1579 delay(500); 1580 break; 1581 } 1582 if (i == 1) { 1583 if (resp < 0) 1584 pstatus(pp, "waiting for %s to come up", 1585 pp->lp); 1586 else 1587 pstatus(pp, 1588 "waiting for access to printer on %s", 1589 pp->lp); 1590 } 1591 sleep(i); 1592 } 1593 pstatus(pp, "sending to %s port %d", ep, port); 1594 } 1595 1596 /* 1597 * Printer is connected to an RS232 port on this host 1598 */ 1599 static void 1600 opentty(pp) 1601 const struct printer *pp; 1602 { 1603 register int i; 1604 1605 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1606 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1607 if (pfd >= 0) { 1608 delay(500); 1609 break; 1610 } 1611 if (errno == ENOENT) { 1612 syslog(LOG_ERR, "%s: %m", pp->lp); 1613 exit(1); 1614 } 1615 if (i == 1) 1616 pstatus(pp, 1617 "waiting for %s to become ready (offline?)", 1618 pp->printer); 1619 sleep(i); 1620 } 1621 if (isatty(pfd)) 1622 setty(pp); 1623 pstatus(pp, "%s is ready and printing", pp->printer); 1624 } 1625 1626 /* 1627 * Printer is on a remote host 1628 */ 1629 static void 1630 openrem(pp) 1631 const struct printer *pp; 1632 { 1633 register int i; 1634 int resp; 1635 void (*savealrm)(int); 1636 1637 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1638 resp = -1; 1639 savealrm = signal(SIGALRM, alarmhandler); 1640 alarm(pp->conn_timeout); 1641 pfd = getport(pp, pp->remote_host, 0); 1642 alarm(0); 1643 (void)signal(SIGALRM, savealrm); 1644 if (pfd >= 0) { 1645 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1646 (char *)0) 1647 == 2 + strlen(pp->remote_queue)) 1648 && (resp = response(pp)) == 0) 1649 break; 1650 (void) close(pfd); 1651 } 1652 if (i == 1) { 1653 if (resp < 0) 1654 pstatus(pp, "waiting for %s to come up", 1655 pp->remote_host); 1656 else { 1657 pstatus(pp, 1658 "waiting for queue to be enabled on %s", 1659 pp->remote_host); 1660 i = 256; 1661 } 1662 } 1663 sleep(i); 1664 } 1665 pstatus(pp, "sending to %s", pp->remote_host); 1666 } 1667 1668 /* 1669 * setup tty lines. 1670 */ 1671 static void 1672 setty(pp) 1673 const struct printer *pp; 1674 { 1675 struct termios ttybuf; 1676 1677 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1678 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1679 exit(1); 1680 } 1681 if (tcgetattr(pfd, &ttybuf) < 0) { 1682 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1683 exit(1); 1684 } 1685 if (pp->baud_rate > 0) 1686 cfsetspeed(&ttybuf, pp->baud_rate); 1687 if (pp->mode_set) { 1688 char *s = strdup(pp->mode_set), *tmp; 1689 1690 while ((tmp = strsep(&s, ",")) != NULL) { 1691 (void) msearch(tmp, &ttybuf); 1692 } 1693 } 1694 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1695 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1696 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1697 } 1698 } 1699 } 1700 1701 #ifdef __STDC__ 1702 #include <stdarg.h> 1703 #else 1704 #include <varargs.h> 1705 #endif 1706 1707 static void 1708 #ifdef __STDC__ 1709 pstatus(const struct printer *pp, const char *msg, ...) 1710 #else 1711 pstatus(pp, msg, va_alist) 1712 const struct printer *pp; 1713 char *msg; 1714 va_dcl 1715 #endif 1716 { 1717 int fd; 1718 char *buf; 1719 va_list ap; 1720 #ifdef __STDC__ 1721 va_start(ap, msg); 1722 #else 1723 va_start(ap); 1724 #endif 1725 1726 umask(0); 1727 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1728 if (fd < 0) { 1729 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1730 exit(1); 1731 } 1732 ftruncate(fd, 0); 1733 vasprintf(&buf, msg, ap); 1734 va_end(ap); 1735 writel(fd, buf, "\n", (char *)0); 1736 close(fd); 1737 free(buf); 1738 } 1739 1740 void 1741 alarmhandler(signo) 1742 { 1743 /* ignored */ 1744 } 1745