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