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