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