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