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