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