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