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