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