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