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