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