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