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