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