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