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