printjob.c revision 27757
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 struct stat stb; 1201 FILE *fp; 1202 1203 pipe(p); 1204 if ((s = dofork(DORETURN)) == 0) { /* child */ 1205 dup2(p[0], 0); 1206 closelog(); 1207 for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++) 1208 (void) close(i); 1209 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1210 cp++; 1211 else 1212 cp = _PATH_SENDMAIL; 1213 execl(_PATH_SENDMAIL, cp, "-t", 0); 1214 exit(0); 1215 } else if (s > 0) { /* parent */ 1216 dup2(p[1], 1); 1217 printf("To: %s@%s\n", user, fromhost); 1218 printf("Subject: %s printer job \"%s\"\n", printer, 1219 *jobname ? jobname : "<unknown>"); 1220 printf("Reply-To: root@%s\n\n", host); 1221 printf("Your printer job "); 1222 if (*jobname) 1223 printf("(%s) ", jobname); 1224 switch (bombed) { 1225 case OK: 1226 printf("\ncompleted successfully\n"); 1227 cp = "OK"; 1228 break; 1229 default: 1230 case FATALERR: 1231 printf("\ncould not be printed\n"); 1232 cp = "FATALERR"; 1233 break; 1234 case NOACCT: 1235 printf("\ncould not be printed without an account on %s\n", host); 1236 cp = "NOACCT"; 1237 break; 1238 case FILTERERR: 1239 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1240 (fp = fopen(tempfile, "r")) == NULL) { 1241 printf("\nhad some errors and may not have printed\n"); 1242 break; 1243 } 1244 printf("\nhad the following errors and may not have printed:\n"); 1245 while ((i = getc(fp)) != EOF) 1246 putchar(i); 1247 (void) fclose(fp); 1248 cp = "FILTERERR"; 1249 break; 1250 case ACCESS: 1251 printf("\nwas not printed because it was not linked to the original file\n"); 1252 cp = "ACCESS"; 1253 } 1254 fflush(stdout); 1255 (void) close(1); 1256 } 1257 (void) close(p[0]); 1258 (void) close(p[1]); 1259 wait(NULL); 1260 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1261 user, *jobname ? jobname : "<unknown>", printer, cp); 1262} 1263 1264/* 1265 * dofork - fork with retries on failure 1266 */ 1267static int 1268dofork(action) 1269 int action; 1270{ 1271 register int i, pid; 1272 1273 for (i = 0; i < 20; i++) { 1274 if ((pid = fork()) < 0) { 1275 sleep((unsigned)(i*i)); 1276 continue; 1277 } 1278 /* 1279 * Child should run as daemon instead of root 1280 */ 1281 if (pid == 0) 1282 setuid(DU); 1283 return(pid); 1284 } 1285 syslog(LOG_ERR, "can't fork"); 1286 1287 switch (action) { 1288 case DORETURN: 1289 return (-1); 1290 default: 1291 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1292 /*FALL THRU*/ 1293 case DOABORT: 1294 exit(1); 1295 } 1296 /*NOTREACHED*/ 1297} 1298 1299/* 1300 * Kill child processes to abort current job. 1301 */ 1302static void 1303abortpr(signo) 1304 int signo; 1305{ 1306 (void) unlink(tempfile); 1307 kill(0, SIGINT); 1308 if (ofilter > 0) 1309 kill(ofilter, SIGCONT); 1310 while (wait(NULL) > 0) 1311 ; 1312 if (ofilter > 0 && tfd != -1) 1313 unlink(tfile); 1314 exit(0); 1315} 1316 1317static void 1318init() 1319{ 1320 int status; 1321 char *s; 1322 1323 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1324 syslog(LOG_ERR, "can't open printer description file"); 1325 exit(1); 1326 } else if (status == -1) { 1327 syslog(LOG_ERR, "unknown printer: %s", printer); 1328 exit(1); 1329 } else if (status == -3) 1330 fatal("potential reference loop detected in printcap file"); 1331 1332 if (cgetstr(bp, "lp", &LP) == -1) 1333 LP = _PATH_DEFDEVLP; 1334 if (cgetstr(bp, "rp", &RP) == -1) 1335 RP = DEFLP; 1336 if (cgetstr(bp, "lo", &LO) == -1) 1337 LO = DEFLOCK; 1338 if (cgetstr(bp, "st", &ST) == -1) 1339 ST = DEFSTAT; 1340 if (cgetstr(bp, "lf", &LF) == -1) 1341 LF = _PATH_CONSOLE; 1342 if (cgetstr(bp, "sd", &SD) == -1) 1343 SD = _PATH_DEFSPOOL; 1344 if (cgetnum(bp, "du", &DU) < 0) 1345 DU = DEFUID; 1346 if (cgetstr(bp,"ff", &FF) == -1) 1347 FF = DEFFF; 1348 if (cgetnum(bp, "pw", &PW) < 0) 1349 PW = DEFWIDTH; 1350 sprintf(&width[2], "%ld", PW); 1351 if (cgetnum(bp, "pl", &PL) < 0) 1352 PL = DEFLENGTH; 1353 sprintf(&length[2], "%ld", PL); 1354 if (cgetnum(bp,"px", &PX) < 0) 1355 PX = 0; 1356 sprintf(&pxwidth[2], "%ld", PX); 1357 if (cgetnum(bp, "py", &PY) < 0) 1358 PY = 0; 1359 sprintf(&pxlength[2], "%ld", PY); 1360 cgetstr(bp, "rm", &RM); 1361 if ((s = checkremote())) 1362 syslog(LOG_WARNING, s); 1363 1364 cgetstr(bp, "af", &AF); 1365 cgetstr(bp, "of", &OF); 1366 cgetstr(bp, "if", &IF); 1367 cgetstr(bp, "rf", &RF); 1368 cgetstr(bp, "tf", &TF); 1369 cgetstr(bp, "nf", &NF); 1370 cgetstr(bp, "df", &DF); 1371 cgetstr(bp, "gf", &GF); 1372 cgetstr(bp, "vf", &VF); 1373 cgetstr(bp, "cf", &CF); 1374 cgetstr(bp, "tr", &TR); 1375 cgetstr(bp, "ms", &MS); 1376 1377 RS = (cgetcap(bp, "rs", ':') != NULL); 1378 SF = (cgetcap(bp, "sf", ':') != NULL); 1379 SH = (cgetcap(bp, "sh", ':') != NULL); 1380 SB = (cgetcap(bp, "sb", ':') != NULL); 1381 HL = (cgetcap(bp, "hl", ':') != NULL); 1382 RW = (cgetcap(bp, "rw", ':') != NULL); 1383 1384 cgetnum(bp, "br", &BR); 1385 1386 tof = (cgetcap(bp, "fo", ':') == NULL); 1387} 1388 1389/* 1390 * Acquire line printer or remote connection. 1391 */ 1392static void 1393openpr() 1394{ 1395 register int i; 1396 int dtablesize; 1397 char *cp; 1398 1399 if (!remote && *LP) { 1400 if (cp = strchr(LP, '@')) 1401 opennet(cp); 1402 else 1403 opentty(); 1404 } else if (remote) { 1405 openrem(); 1406 } else { 1407 syslog(LOG_ERR, "%s: no line printer device or host name", 1408 printer); 1409 exit(1); 1410 } 1411 1412 /* 1413 * Start up an output filter, if needed. 1414 */ 1415 if (OF && !IF && !ofilter) { 1416 int p[2]; 1417 1418 pipe(p); 1419 if (remote) { 1420 strcpy(tfile,TFILENAME); 1421 tfd = mkstemp(tfile); 1422 } 1423 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1424 dup2(p[0], 0); /* pipe is std in */ 1425 /* tfile/printer is stdout */ 1426 dup2(remote ? tfd : pfd, 1); 1427 closelog(); 1428 for (i = 3, dtablesize = getdtablesize(); 1429 i < dtablesize; i++) 1430 (void) close(i); 1431 if ((cp = strrchr(OF, '/')) == NULL) 1432 cp = OF; 1433 else 1434 cp++; 1435 execl(OF, cp, width, length, 0); 1436 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1437 exit(1); 1438 } 1439 (void) close(p[0]); /* close input side */ 1440 ofd = p[1]; /* use pipe for output */ 1441 } else { 1442 ofd = pfd; 1443 ofilter = 0; 1444 } 1445} 1446 1447/* 1448 * Printer connected directly to the network 1449 * or to a terminal server on the net 1450 */ 1451static void 1452opennet(cp) 1453 char *cp; 1454{ 1455 register int i; 1456 int resp, port; 1457 char save_ch; 1458 1459 save_ch = *cp; 1460 *cp = '\0'; 1461 port = atoi(LP); 1462 if (port <= 0) { 1463 syslog(LOG_ERR, "%s: bad port number: %s", printer, LP); 1464 exit(1); 1465 } 1466 *cp++ = save_ch; 1467 1468 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1469 resp = -1; 1470 pfd = getport(cp, port); 1471 if (pfd < 0 && errno == ECONNREFUSED) 1472 resp = 1; 1473 else if (pfd >= 0) { 1474 /* 1475 * need to delay a bit for rs232 lines 1476 * to stabilize in case printer is 1477 * connected via a terminal server 1478 */ 1479 delay(500); 1480 break; 1481 } 1482 if (i == 1) { 1483 if (resp < 0) 1484 pstatus("waiting for %s to come up", LP); 1485 else 1486 pstatus("waiting for access to printer on %s", LP); 1487 } 1488 sleep(i); 1489 } 1490 pstatus("sending to %s port %d", cp, port); 1491} 1492 1493/* 1494 * Printer is connected to an RS232 port on this host 1495 */ 1496static void 1497opentty() 1498{ 1499 register int i; 1500 int resp, port; 1501 1502 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1503 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1504 if (pfd >= 0) { 1505 delay(500); 1506 break; 1507 } 1508 if (errno == ENOENT) { 1509 syslog(LOG_ERR, "%s: %m", LP); 1510 exit(1); 1511 } 1512 if (i == 1) 1513 pstatus("waiting for %s to become ready (offline ?)", 1514 printer); 1515 sleep(i); 1516 } 1517 if (isatty(pfd)) 1518 setty(); 1519 pstatus("%s is ready and printing", printer); 1520} 1521 1522/* 1523 * Printer is on a remote host 1524 */ 1525static void 1526openrem() 1527{ 1528 register int i, n; 1529 int resp; 1530 1531 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1532 resp = -1; 1533 pfd = getport(RM, 0); 1534 if (pfd >= 0) { 1535 (void) snprintf(line, sizeof(line), "\2%s\n", RP); 1536 n = strlen(line); 1537 if (write(pfd, line, n) == n && 1538 (resp = response()) == '\0') 1539 break; 1540 (void) close(pfd); 1541 } 1542 if (i == 1) { 1543 if (resp < 0) 1544 pstatus("waiting for %s to come up", RM); 1545 else { 1546 pstatus("waiting for queue to be enabled on %s", 1547 RM); 1548 i = 256; 1549 } 1550 } 1551 sleep(i); 1552 } 1553 pstatus("sending to %s", RM); 1554} 1555 1556struct bauds { 1557 int baud; 1558 int speed; 1559} bauds[] = { 1560 50, B50, 1561 75, B75, 1562 110, B110, 1563 134, B134, 1564 150, B150, 1565 200, B200, 1566 300, B300, 1567 600, B600, 1568 1200, B1200, 1569 1800, B1800, 1570 2400, B2400, 1571 4800, B4800, 1572 9600, B9600, 1573 19200, EXTA, 1574 38400, EXTB, 1575 57600, B57600, 1576 115200, B115200, 1577 0, 0 1578}; 1579 1580/* 1581 * setup tty lines. 1582 */ 1583static void 1584setty() 1585{ 1586 struct termios ttybuf; 1587 struct bauds *bp; 1588 1589 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1590 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1591 exit(1); 1592 } 1593 if (tcgetattr(pfd, &ttybuf) < 0) { 1594 syslog(LOG_ERR, "%s: tcgetattr: %m", printer); 1595 exit(1); 1596 } 1597 if (BR > 0) { 1598 for (bp = bauds; bp->baud; bp++) 1599 if (BR == bp->baud) 1600 break; 1601 if (!bp->baud) { 1602 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1603 exit(1); 1604 } 1605 cfsetspeed(&ttybuf, bp->speed); 1606 } 1607 if (MS) { 1608 char *s = strdup(MS), *tmp; 1609 1610 while (tmp = strsep (&s, ",")) { 1611 msearch(tmp, &ttybuf); 1612 } 1613 } 1614 if (MS || (BR > 0)) { 1615 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1616 syslog(LOG_ERR, "%s: tcsetattr: %m", printer); 1617 } 1618 } 1619} 1620 1621#ifdef __STDC__ 1622#include <stdarg.h> 1623#else 1624#include <varargs.h> 1625#endif 1626 1627static void 1628#ifdef __STDC__ 1629pstatus(const char *msg, ...) 1630#else 1631pstatus(msg, va_alist) 1632 char *msg; 1633 va_dcl 1634#endif 1635{ 1636 register int fd; 1637 char buf[BUFSIZ]; 1638 va_list ap; 1639#ifdef __STDC__ 1640 va_start(ap, msg); 1641#else 1642 va_start(ap); 1643#endif 1644 1645 umask(0); 1646 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1647 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1648 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1649 exit(1); 1650 } 1651 ftruncate(fd, 0); 1652 (void)vsnprintf(buf, sizeof(buf) - 1, msg, ap); 1653 va_end(ap); 1654 strcat(buf, "\n"); 1655 (void) write(fd, buf, strlen(buf)); 1656 (void) close(fd); 1657} 1658