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