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