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