printjob.c revision 68734
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 68734 2000-11-14 22:03:59Z 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, didignorehdr; 359 360 bombed = OK; 361 didignorehdr = 0; 362 /* 363 * open control file; ignore if no longer there. 364 */ 365 if ((cfp = fopen(file, "r")) == NULL) { 366 syslog(LOG_INFO, "%s: %s: %m", pp->printer, file); 367 return(OK); 368 } 369 /* 370 * Reset troff fonts. 371 */ 372 for (i = 0; i < 4; i++) 373 strcpy(fonts[i], ifonts[i]); 374 sprintf(&width[2], "%ld", pp->page_width); 375 strcpy(indent+2, "0"); 376 377 /* initialize job-specific count of datafiles processed */ 378 job_dfcnt = 0; 379 380 /* 381 * read the control file for work to do 382 * 383 * file format -- first character in the line is a command 384 * rest of the line is the argument. 385 * valid commands are: 386 * 387 * S -- "stat info" for symbolic link protection 388 * J -- "job name" on banner page 389 * C -- "class name" on banner page 390 * L -- "literal" user's name to print on banner 391 * T -- "title" for pr 392 * H -- "host name" of machine where lpr was done 393 * P -- "person" user's login name 394 * I -- "indent" amount to indent output 395 * R -- laser dpi "resolution" 396 * f -- "file name" name of text file to print 397 * l -- "file name" text file with control chars 398 * p -- "file name" text file to print with pr(1) 399 * t -- "file name" troff(1) file to print 400 * n -- "file name" ditroff(1) file to print 401 * d -- "file name" dvi file to print 402 * g -- "file name" plot(1G) file to print 403 * v -- "file name" plain raster file to print 404 * c -- "file name" cifplot file to print 405 * 1 -- "R font file" for troff 406 * 2 -- "I font file" for troff 407 * 3 -- "B font file" for troff 408 * 4 -- "S font file" for troff 409 * N -- "name" of file (used by lpq) 410 * U -- "unlink" name of file to remove 411 * (after we print it. (Pass 2 only)). 412 * M -- "mail" to user when done printing 413 * Z -- "locale" for pr 414 * 415 * getline reads a line and expands tabs to blanks 416 */ 417 418 /* pass 1 */ 419 420 while (getline(cfp)) 421 switch (line[0]) { 422 case 'H': 423 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 424 fromhost[sizeof(fromhost) - 1] = '\0'; 425 if (class[0] == '\0') { 426 strncpy(class, line+1, sizeof(class) - 1); 427 class[sizeof(class) - 1] = '\0'; 428 } 429 continue; 430 431 case 'P': 432 strncpy(logname, line+1, sizeof(logname) - 1); 433 logname[sizeof(logname) - 1] = '\0'; 434 if (pp->restricted) { /* restricted */ 435 if (getpwnam(logname) == NULL) { 436 bombed = NOACCT; 437 sendmail(pp, line+1, bombed); 438 goto pass2; 439 } 440 } 441 continue; 442 443 case 'S': 444 cp = line+1; 445 i = 0; 446 while (*cp >= '0' && *cp <= '9') 447 i = i * 10 + (*cp++ - '0'); 448 fdev = i; 449 cp++; 450 i = 0; 451 while (*cp >= '0' && *cp <= '9') 452 i = i * 10 + (*cp++ - '0'); 453 fino = i; 454 continue; 455 456 case 'J': 457 if (line[1] != '\0') { 458 strncpy(jobname, line+1, sizeof(jobname) - 1); 459 jobname[sizeof(jobname) - 1] = '\0'; 460 } else 461 strcpy(jobname, " "); 462 continue; 463 464 case 'C': 465 if (line[1] != '\0') 466 strncpy(class, line+1, sizeof(class) - 1); 467 else if (class[0] == '\0') 468 gethostname(class, sizeof(class)); 469 class[sizeof(class) - 1] = '\0'; 470 continue; 471 472 case 'T': /* header title for pr */ 473 strncpy(title, line+1, sizeof(title) - 1); 474 title[sizeof(title) - 1] = '\0'; 475 continue; 476 477 case 'L': /* identification line */ 478 if (!pp->no_header && !pp->header_last) 479 banner(pp, line+1, jobname); 480 continue; 481 482 case '1': /* troff fonts */ 483 case '2': 484 case '3': 485 case '4': 486 if (line[1] != '\0') { 487 strncpy(fonts[line[0]-'1'], line+1, 488 50-1); 489 fonts[line[0]-'1'][50-1] = '\0'; 490 } 491 continue; 492 493 case 'W': /* page width */ 494 strncpy(width+2, line+1, sizeof(width) - 3); 495 width[2+sizeof(width) - 3] = '\0'; 496 continue; 497 498 case 'I': /* indent amount */ 499 strncpy(indent+2, line+1, sizeof(indent) - 3); 500 indent[2+sizeof(indent) - 3] = '\0'; 501 continue; 502 503 case 'Z': /* locale for pr */ 504 strncpy(locale, line+1, sizeof(locale) - 1); 505 locale[sizeof(locale) - 1] = '\0'; 506 continue; 507 508 default: /* some file to print */ 509 /* only lowercase cmd-codes include a file-to-print */ 510 if ((line[0] < 'a') || (line[0] > 'z')) { 511 /* ignore any other lines */ 512 if (lflag <= 1) 513 continue; 514 if (!didignorehdr) { 515 syslog(LOG_INFO, "%s: in %s :", 516 pp->printer, file); 517 didignorehdr = 1; 518 } 519 syslog(LOG_INFO, "%s: ignoring line: '%c' %s", 520 pp->printer, line[0], &line[1]); 521 continue; 522 } 523 i = print(pp, line[0], line+1); 524 switch (i) { 525 case ERROR: 526 if (bombed == OK) 527 bombed = FATALERR; 528 break; 529 case REPRINT: 530 (void) fclose(cfp); 531 return(REPRINT); 532 case FILTERERR: 533 case ACCESS: 534 bombed = i; 535 sendmail(pp, logname, bombed); 536 } 537 title[0] = '\0'; 538 continue; 539 540 case 'N': 541 case 'U': 542 case 'M': 543 case 'R': 544 continue; 545 } 546 547 /* pass 2 */ 548 549pass2: 550 fseek(cfp, 0L, 0); 551 while (getline(cfp)) 552 switch (line[0]) { 553 case 'L': /* identification line */ 554 if (!pp->no_header && pp->header_last) 555 banner(pp, line+1, jobname); 556 continue; 557 558 case 'M': 559 if (bombed < NOACCT) /* already sent if >= NOACCT */ 560 sendmail(pp, line+1, bombed); 561 continue; 562 563 case 'U': 564 if (strchr(line+1, '/')) 565 continue; 566 (void) unlink(line+1); 567 } 568 /* 569 * clean-up in case another control file exists 570 */ 571 (void) fclose(cfp); 572 (void) unlink(file); 573 return(bombed == OK ? OK : ERROR); 574} 575 576/* 577 * Print a file. 578 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 579 * Return -1 if a non-recoverable error occured, 580 * 2 if the filter detected some errors (but printed the job anyway), 581 * 1 if we should try to reprint this job and 582 * 0 if all is well. 583 * Note: all filters take stdin as the file, stdout as the printer, 584 * stderr as the log file, and must not ignore SIGINT. 585 */ 586static int 587print(pp, format, file) 588 struct printer *pp; 589 int format; 590 char *file; 591{ 592 register int n, i; 593 register char *prog; 594 int fi, fo; 595 FILE *fp; 596 char *av[15], buf[BUFSIZ]; 597 int pid, p[2], stopped; 598 union wait status; 599 struct stat stb; 600 601 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) { 602 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)", 603 pp->printer, file, format); 604 return(ERROR); 605 } 606 /* 607 * Check to see if data file is a symbolic link. If so, it should 608 * still point to the same file or someone is trying to print 609 * something he shouldn't. 610 */ 611 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 612 (stb.st_dev != fdev || stb.st_ino != fino)) 613 return(ACCESS); 614 615 job_dfcnt++; /* increment datafile counter for this job */ 616 stopped = 0; /* output filter is not stopped */ 617 618 /* everything seems OK, start it up */ 619 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */ 620 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 621 pp->tof = 1; 622 } 623 if (pp->filters[LPF_INPUT] == NULL 624 && (format == 'f' || format == 'l')) { 625 pp->tof = 0; 626 while ((n = read(fi, buf, BUFSIZ)) > 0) 627 if (write(ofd, buf, n) != n) { 628 (void) close(fi); 629 return(REPRINT); 630 } 631 (void) close(fi); 632 return(OK); 633 } 634 switch (format) { 635 case 'p': /* print file using 'pr' */ 636 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */ 637 prog = _PATH_PR; 638 i = 0; 639 av[i++] = "pr"; 640 av[i++] = width; 641 av[i++] = length; 642 av[i++] = "-h"; 643 av[i++] = *title ? title : " "; 644 av[i++] = "-L"; 645 av[i++] = *locale ? locale : "C"; 646 av[i++] = "-F"; 647 av[i] = 0; 648 fo = ofd; 649 goto start; 650 } 651 pipe(p); 652 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */ 653 dup2(fi, 0); /* file is stdin */ 654 dup2(p[1], 1); /* pipe is stdout */ 655 closelog(); 656 closeallfds(3); 657 execl(_PATH_PR, "pr", width, length, 658 "-h", *title ? title : " ", 659 "-L", *locale ? locale : "C", 660 "-F", 0); 661 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 662 exit(2); 663 } 664 (void) close(p[1]); /* close output side */ 665 (void) close(fi); 666 if (prchild < 0) { 667 prchild = 0; 668 (void) close(p[0]); 669 return(ERROR); 670 } 671 fi = p[0]; /* use pipe for input */ 672 case 'f': /* print plain text file */ 673 prog = pp->filters[LPF_INPUT]; 674 av[1] = width; 675 av[2] = length; 676 av[3] = indent; 677 n = 4; 678 break; 679 case 'l': /* like 'f' but pass control characters */ 680 prog = pp->filters[LPF_INPUT]; 681 av[1] = "-c"; 682 av[2] = width; 683 av[3] = length; 684 av[4] = indent; 685 n = 5; 686 break; 687 case 'r': /* print a fortran text file */ 688 prog = pp->filters[LPF_FORTRAN]; 689 av[1] = width; 690 av[2] = length; 691 n = 3; 692 break; 693 case 't': /* print troff output */ 694 case 'n': /* print ditroff output */ 695 case 'd': /* print tex output */ 696 (void) unlink(".railmag"); 697 if ((fo = creat(".railmag", FILMOD)) < 0) { 698 syslog(LOG_ERR, "%s: cannot create .railmag", 699 pp->printer); 700 (void) unlink(".railmag"); 701 } else { 702 for (n = 0; n < 4; n++) { 703 if (fonts[n][0] != '/') 704 (void) write(fo, _PATH_VFONT, 705 sizeof(_PATH_VFONT) - 1); 706 (void) write(fo, fonts[n], strlen(fonts[n])); 707 (void) write(fo, "\n", 1); 708 } 709 (void) close(fo); 710 } 711 prog = (format == 't') ? pp->filters[LPF_TROFF] 712 : ((format == 'n') ? pp->filters[LPF_DITROFF] 713 : pp->filters[LPF_DVI]); 714 av[1] = pxwidth; 715 av[2] = pxlength; 716 n = 3; 717 break; 718 case 'c': /* print cifplot output */ 719 prog = pp->filters[LPF_CIFPLOT]; 720 av[1] = pxwidth; 721 av[2] = pxlength; 722 n = 3; 723 break; 724 case 'g': /* print plot(1G) output */ 725 prog = pp->filters[LPF_GRAPH]; 726 av[1] = pxwidth; 727 av[2] = pxlength; 728 n = 3; 729 break; 730 case 'v': /* print raster output */ 731 prog = pp->filters[LPF_RASTER]; 732 av[1] = pxwidth; 733 av[2] = pxlength; 734 n = 3; 735 break; 736 default: 737 (void) close(fi); 738 syslog(LOG_ERR, "%s: illegal format character '%c'", 739 pp->printer, format); 740 return(ERROR); 741 } 742 if (prog == NULL) { 743 (void) close(fi); 744 syslog(LOG_ERR, 745 "%s: no filter found in printcap for format character '%c'", 746 pp->printer, format); 747 return(ERROR); 748 } 749 if ((av[0] = strrchr(prog, '/')) != NULL) 750 av[0]++; 751 else 752 av[0] = prog; 753 av[n++] = "-n"; 754 av[n++] = logname; 755 av[n++] = "-h"; 756 av[n++] = fromhost; 757 av[n++] = pp->acct_file; 758 av[n] = 0; 759 fo = pfd; 760 if (ofilter > 0) { /* stop output filter */ 761 write(ofd, "\031\1", 2); 762 while ((pid = 763 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 764 ; 765 if (status.w_stopval != WSTOPPED) { 766 (void) close(fi); 767 syslog(LOG_WARNING, 768 "%s: output filter died " 769 "(retcode=%d termsig=%d)", 770 pp->printer, status.w_retcode, 771 status.w_termsig); 772 return(REPRINT); 773 } 774 stopped++; 775 } 776start: 777 if ((child = dofork(pp, DORETURN)) == 0) { /* child */ 778 dup2(fi, 0); 779 dup2(fo, 1); 780 /* setup stderr for the filter (child process) 781 * so it goes to our temporary errors file */ 782 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 783 if (n >= 0) 784 dup2(n, 2); 785 closelog(); 786 closeallfds(3); 787 execv(prog, av); 788 syslog(LOG_ERR, "cannot execv %s", prog); 789 exit(2); 790 } 791 (void) close(fi); 792 if (child < 0) 793 status.w_retcode = 100; 794 else 795 while ((pid = wait((int *)&status)) > 0 && pid != child) 796 ; 797 child = 0; 798 prchild = 0; 799 if (stopped) { /* restart output filter */ 800 if (kill(ofilter, SIGCONT) < 0) { 801 syslog(LOG_ERR, "cannot restart output filter"); 802 exit(1); 803 } 804 } 805 pp->tof = 0; 806 807 /* Copy the filter's output to "lf" logfile */ 808 if ((fp = fopen(tempstderr, "r"))) { 809 while (fgets(buf, sizeof(buf), fp)) 810 fputs(buf, stderr); 811 fclose(fp); 812 } 813 814 if (!WIFEXITED(status)) { 815 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)", 816 pp->printer, format, status.w_termsig); 817 return(ERROR); 818 } 819 switch (status.w_retcode) { 820 case 0: 821 pp->tof = 1; 822 return(OK); 823 case 1: 824 return(REPRINT); 825 case 2: 826 return(ERROR); 827 default: 828 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 829 pp->printer, format, status.w_retcode); 830 return(FILTERERR); 831 } 832} 833 834/* 835 * Send the daemon control file (cf) and any data files. 836 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 837 * 0 if all is well. 838 */ 839static int 840sendit(pp, file) 841 struct printer *pp; 842 char *file; 843{ 844 register int i, err = OK; 845 char *cp, last[BUFSIZ]; 846 847 /* 848 * open control file 849 */ 850 if ((cfp = fopen(file, "r")) == NULL) 851 return(OK); 852 853 /* initialize job-specific count of datafiles processed */ 854 job_dfcnt = 0; 855 856 /* 857 * read the control file for work to do 858 * 859 * file format -- first character in the line is a command 860 * rest of the line is the argument. 861 * commands of interest are: 862 * 863 * a-z -- "file name" name of file to print 864 * U -- "unlink" name of file to remove 865 * (after we print it. (Pass 2 only)). 866 */ 867 868 /* 869 * pass 1 870 */ 871 while (getline(cfp)) { 872 again: 873 if (line[0] == 'S') { 874 cp = line+1; 875 i = 0; 876 while (*cp >= '0' && *cp <= '9') 877 i = i * 10 + (*cp++ - '0'); 878 fdev = i; 879 cp++; 880 i = 0; 881 while (*cp >= '0' && *cp <= '9') 882 i = i * 10 + (*cp++ - '0'); 883 fino = i; 884 } else if (line[0] == 'H') { 885 strncpy(fromhost, line+1, sizeof(fromhost) - 1); 886 fromhost[sizeof(fromhost) - 1] = '\0'; 887 if (class[0] == '\0') { 888 strncpy(class, line+1, sizeof(class) - 1); 889 class[sizeof(class) - 1] = '\0'; 890 } 891 } else if (line[0] == 'P') { 892 strncpy(logname, line+1, sizeof(logname) - 1); 893 if (pp->restricted) { /* restricted */ 894 if (getpwnam(logname) == NULL) { 895 sendmail(pp, line+1, NOACCT); 896 err = ERROR; 897 break; 898 } 899 } 900 } else if (line[0] == 'I') { 901 strncpy(indent+2, line+1, sizeof(indent) - 3); 902 } else if (line[0] >= 'a' && line[0] <= 'z') { 903 strcpy(last, line); 904 while ((i = getline(cfp)) != 0) 905 if (strcmp(last, line)) 906 break; 907 switch (sendfile(pp, '\3', last+1, *last)) { 908 case OK: 909 if (i) 910 goto again; 911 break; 912 case REPRINT: 913 (void) fclose(cfp); 914 return(REPRINT); 915 case ACCESS: 916 sendmail(pp, logname, ACCESS); 917 case ERROR: 918 err = ERROR; 919 } 920 break; 921 } 922 } 923 if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { 924 (void) fclose(cfp); 925 return(REPRINT); 926 } 927 /* 928 * pass 2 929 */ 930 fseek(cfp, 0L, 0); 931 while (getline(cfp)) 932 if (line[0] == 'U' && !strchr(line+1, '/')) 933 (void) unlink(line+1); 934 /* 935 * clean-up in case another control file exists 936 */ 937 (void) fclose(cfp); 938 (void) unlink(file); 939 return(err); 940} 941 942/* 943 * Send a data file to the remote machine and spool it. 944 * Return positive if we should try resending. 945 */ 946static int 947sendfile(pp, type, file, format) 948 struct printer *pp; 949 int type; 950 char *file; 951 char format; 952{ 953 register int f, i, amt; 954 struct stat stb; 955 FILE *fp; 956 char buf[BUFSIZ]; 957 int sizerr, resp, closedpr; 958 959 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 960 return(ERROR); 961 /* 962 * Check to see if data file is a symbolic link. If so, it should 963 * still point to the same file or someone is trying to print something 964 * he shouldn't. 965 */ 966 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 967 (stb.st_dev != fdev || stb.st_ino != fino)) 968 return(ACCESS); 969 970 job_dfcnt++; /* increment datafile counter for this job */ 971 972 /* everything seems OK, start it up */ 973 sizerr = 0; 974 closedpr = 0; 975 if (type == '\3') { 976 if (pp->filters[LPF_INPUT]) { 977 /* 978 * We're sending something with an ifilter, we have to 979 * run the ifilter and store the output as a 980 * temporary file (tfile)... the protocol requires us 981 * to send the file size 982 */ 983 char *av[15]; 984 int n; 985 int ifilter; 986 union wait status; /* XXX */ 987 988 strcpy(tfile,TFILENAME); 989 if ((tfd = mkstemp(tfile)) == -1) { 990 syslog(LOG_ERR, "mkstemp: %m"); 991 return(ERROR); 992 } 993 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL) 994 av[0] = pp->filters[LPF_INPUT]; 995 else 996 av[0]++; 997 if (format == 'l') 998 av[n=1] = "-c"; 999 else 1000 n = 0; 1001 av[++n] = width; 1002 av[++n] = length; 1003 av[++n] = indent; 1004 av[++n] = "-n"; 1005 av[++n] = logname; 1006 av[++n] = "-h"; 1007 av[++n] = fromhost; 1008 av[++n] = pp->acct_file; 1009 av[++n] = 0; 1010 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */ 1011 dup2(f, 0); 1012 dup2(tfd, 1); 1013 /* setup stderr for the filter (child process) 1014 * so it goes to our temporary errors file */ 1015 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1016 if (n >= 0) 1017 dup2(n, 2); 1018 closelog(); 1019 closeallfds(3); 1020 execv(pp->filters[LPF_INPUT], av); 1021 syslog(LOG_ERR, "cannot execv %s", 1022 pp->filters[LPF_INPUT]); 1023 exit(2); 1024 } 1025 (void) close(f); 1026 if (ifilter < 0) 1027 status.w_retcode = 100; 1028 else 1029 while ((pid = wait((int *)&status)) > 0 && 1030 pid != ifilter) 1031 ; 1032 /* Copy the filter's output to "lf" logfile */ 1033 if ((fp = fopen(tempstderr, "r"))) { 1034 while (fgets(buf, sizeof(buf), fp)) 1035 fputs(buf, stderr); 1036 fclose(fp); 1037 } 1038 /* process the return-code from the filter */ 1039 switch (status.w_retcode) { 1040 case 0: 1041 break; 1042 case 1: 1043 unlink(tfile); 1044 return(REPRINT); 1045 case 2: 1046 unlink(tfile); 1047 return(ERROR); 1048 default: 1049 syslog(LOG_WARNING, "%s: filter '%c' exited" 1050 " (retcode=%d)", 1051 pp->printer, format, status.w_retcode); 1052 unlink(tfile); 1053 return(FILTERERR); 1054 } 1055 if (fstat(tfd, &stb) < 0) /* the size of tfile */ 1056 return(ERROR); 1057 f = tfd; 1058 lseek(f,0,SEEK_SET); 1059 } else if (ofilter) { 1060 /* 1061 * We're sending something with an ofilter, we have to 1062 * store the output as a temporary file (tfile)... the 1063 * protocol requires us to send the file size 1064 */ 1065 int i; 1066 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1067 amt = BUFSIZ; 1068 if (i + amt > stb.st_size) 1069 amt = stb.st_size - i; 1070 if (sizerr == 0 && read(f, buf, amt) != amt) { 1071 sizerr = 1; 1072 break; 1073 } 1074 if (write(ofd, buf, amt) != amt) { 1075 (void) close(f); 1076 return(REPRINT); 1077 } 1078 } 1079 close(ofd); 1080 close(f); 1081 while ((i = wait(NULL)) > 0 && i != ofilter) 1082 ; 1083 ofilter = 0; 1084 if (fstat(tfd, &stb) < 0) { /* the size of tfile */ 1085 openpr(pp); 1086 return(ERROR); 1087 } 1088 f = tfd; 1089 lseek(f,0,SEEK_SET); 1090 closedpr = 1; 1091 } 1092 } 1093 1094 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1095 amt = strlen(buf); 1096 for (i = 0; ; i++) { 1097 if (write(pfd, buf, amt) != amt || 1098 (resp = response(pp)) < 0 || resp == '\1') { 1099 (void) close(f); 1100 if (tfd != -1 && type == '\3') { 1101 tfd = -1; 1102 unlink(tfile); 1103 if (closedpr) 1104 openpr(pp); 1105 } 1106 return(REPRINT); 1107 } else if (resp == '\0') 1108 break; 1109 if (i == 0) 1110 pstatus(pp, 1111 "no space on remote; waiting for queue to drain"); 1112 if (i == 10) 1113 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 1114 pp->printer, pp->remote_host); 1115 sleep(5 * 60); 1116 } 1117 if (i) 1118 pstatus(pp, "sending to %s", pp->remote_host); 1119 if (type == '\3') 1120 trstat_init(pp, file, job_dfcnt); 1121 for (i = 0; i < stb.st_size; i += BUFSIZ) { 1122 amt = BUFSIZ; 1123 if (i + amt > stb.st_size) 1124 amt = stb.st_size - i; 1125 if (sizerr == 0 && read(f, buf, amt) != amt) 1126 sizerr = 1; 1127 if (write(pfd, buf, amt) != amt) { 1128 (void) close(f); 1129 if (tfd != -1 && type == '\3') { 1130 tfd = -1; 1131 unlink(tfile); 1132 if (closedpr) 1133 openpr(pp); 1134 } 1135 return(REPRINT); 1136 } 1137 } 1138 1139 (void) close(f); 1140 if (tfd != -1 && type == '\3') { 1141 tfd = -1; 1142 unlink(tfile); 1143 } 1144 if (sizerr) { 1145 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1146 /* tell recvjob to ignore this file */ 1147 (void) write(pfd, "\1", 1); 1148 if (closedpr) 1149 openpr(pp); 1150 return(ERROR); 1151 } 1152 if (write(pfd, "", 1) != 1 || response(pp)) { 1153 if (closedpr) 1154 openpr(pp); 1155 return(REPRINT); 1156 } 1157 if (closedpr) 1158 openpr(pp); 1159 if (type == '\3') 1160 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1161 pp->remote_host, fromhost); 1162 return(OK); 1163} 1164 1165/* 1166 * Check to make sure there have been no errors and that both programs 1167 * are in sync with eachother. 1168 * Return non-zero if the connection was lost. 1169 */ 1170static char 1171response(pp) 1172 const struct printer *pp; 1173{ 1174 char resp; 1175 1176 if (read(pfd, &resp, 1) != 1) { 1177 syslog(LOG_INFO, "%s: lost connection", pp->printer); 1178 return(-1); 1179 } 1180 return(resp); 1181} 1182 1183/* 1184 * Banner printing stuff 1185 */ 1186static void 1187banner(pp, name1, name2) 1188 struct printer *pp; 1189 char *name1, *name2; 1190{ 1191 time_t tvec; 1192 1193 time(&tvec); 1194 if (!pp->no_formfeed && !pp->tof) 1195 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1196 if (pp->short_banner) { /* short banner only */ 1197 if (class[0]) { 1198 (void) write(ofd, class, strlen(class)); 1199 (void) write(ofd, ":", 1); 1200 } 1201 (void) write(ofd, name1, strlen(name1)); 1202 (void) write(ofd, " Job: ", 7); 1203 (void) write(ofd, name2, strlen(name2)); 1204 (void) write(ofd, " Date: ", 8); 1205 (void) write(ofd, ctime(&tvec), 24); 1206 (void) write(ofd, "\n", 1); 1207 } else { /* normal banner */ 1208 (void) write(ofd, "\n\n\n", 3); 1209 scan_out(pp, ofd, name1, '\0'); 1210 (void) write(ofd, "\n\n", 2); 1211 scan_out(pp, ofd, name2, '\0'); 1212 if (class[0]) { 1213 (void) write(ofd,"\n\n\n",3); 1214 scan_out(pp, ofd, class, '\0'); 1215 } 1216 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1217 (void) write(ofd, name2, strlen(name2)); 1218 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 1219 (void) write(ofd, ctime(&tvec), 24); 1220 (void) write(ofd, "\n", 1); 1221 } 1222 if (!pp->no_formfeed) 1223 (void) write(ofd, pp->form_feed, strlen(pp->form_feed)); 1224 pp->tof = 1; 1225} 1226 1227static char * 1228scnline(key, p, c) 1229 register int key; 1230 register char *p; 1231 int c; 1232{ 1233 register int scnwidth; 1234 1235 for (scnwidth = WIDTH; --scnwidth;) { 1236 key <<= 1; 1237 *p++ = key & 0200 ? c : BACKGND; 1238 } 1239 return (p); 1240} 1241 1242#define TRC(q) (((q)-' ')&0177) 1243 1244static void 1245scan_out(pp, scfd, scsp, dlm) 1246 struct printer *pp; 1247 int scfd, dlm; 1248 char *scsp; 1249{ 1250 register char *strp; 1251 register int nchrs, j; 1252 char outbuf[LINELEN+1], *sp, c, cc; 1253 int d, scnhgt; 1254 1255 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1256 strp = &outbuf[0]; 1257 sp = scsp; 1258 for (nchrs = 0; ; ) { 1259 d = dropit(c = TRC(cc = *sp++)); 1260 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1261 for (j = WIDTH; --j;) 1262 *strp++ = BACKGND; 1263 else 1264 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc); 1265 if (*sp == dlm || *sp == '\0' || 1266 nchrs++ >= pp->page_width/(WIDTH+1)-1) 1267 break; 1268 *strp++ = BACKGND; 1269 *strp++ = BACKGND; 1270 } 1271 while (*--strp == BACKGND && strp >= outbuf) 1272 ; 1273 strp++; 1274 *strp++ = '\n'; 1275 (void) write(scfd, outbuf, strp-outbuf); 1276 } 1277} 1278 1279static int 1280dropit(c) 1281 int c; 1282{ 1283 switch(c) { 1284 1285 case TRC('_'): 1286 case TRC(';'): 1287 case TRC(','): 1288 case TRC('g'): 1289 case TRC('j'): 1290 case TRC('p'): 1291 case TRC('q'): 1292 case TRC('y'): 1293 return (DROP); 1294 1295 default: 1296 return (0); 1297 } 1298} 1299 1300/* 1301 * sendmail --- 1302 * tell people about job completion 1303 */ 1304static void 1305sendmail(pp, user, bombed) 1306 struct printer *pp; 1307 char *user; 1308 int bombed; 1309{ 1310 register int i; 1311 int p[2], s; 1312 register char *cp; 1313 struct stat stb; 1314 FILE *fp; 1315 1316 pipe(p); 1317 if ((s = dofork(pp, DORETURN)) == 0) { /* child */ 1318 dup2(p[0], 0); 1319 closelog(); 1320 closeallfds(3); 1321 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1322 cp++; 1323 else 1324 cp = _PATH_SENDMAIL; 1325 execl(_PATH_SENDMAIL, cp, "-t", 0); 1326 _exit(0); 1327 } else if (s > 0) { /* parent */ 1328 dup2(p[1], 1); 1329 printf("To: %s@%s\n", user, fromhost); 1330 printf("Subject: %s printer job \"%s\"\n", pp->printer, 1331 *jobname ? jobname : "<unknown>"); 1332 printf("Reply-To: root@%s\n\n", host); 1333 printf("Your printer job "); 1334 if (*jobname) 1335 printf("(%s) ", jobname); 1336 1337 cp = "XXX compiler confusion"; /* XXX shut GCC up */ 1338 switch (bombed) { 1339 case OK: 1340 printf("\ncompleted successfully\n"); 1341 cp = "OK"; 1342 break; 1343 default: 1344 case FATALERR: 1345 printf("\ncould not be printed\n"); 1346 cp = "FATALERR"; 1347 break; 1348 case NOACCT: 1349 printf("\ncould not be printed without an account on %s\n", host); 1350 cp = "NOACCT"; 1351 break; 1352 case FILTERERR: 1353 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0 1354 || (fp = fopen(tempstderr, "r")) == NULL) { 1355 printf("\nhad some errors and may not have printed\n"); 1356 break; 1357 } 1358 printf("\nhad the following errors and may not have printed:\n"); 1359 while ((i = getc(fp)) != EOF) 1360 putchar(i); 1361 (void) fclose(fp); 1362 cp = "FILTERERR"; 1363 break; 1364 case ACCESS: 1365 printf("\nwas not printed because it was not linked to the original file\n"); 1366 cp = "ACCESS"; 1367 } 1368 fflush(stdout); 1369 (void) close(1); 1370 } else { 1371 syslog(LOG_WARNING, "unable to send mail to %s: %m", user); 1372 return; 1373 } 1374 (void) close(p[0]); 1375 (void) close(p[1]); 1376 wait(NULL); 1377 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)", 1378 user, *jobname ? jobname : "<unknown>", pp->printer, cp); 1379} 1380 1381/* 1382 * dofork - fork with retries on failure 1383 */ 1384static int 1385dofork(pp, action) 1386 const struct printer *pp; 1387 int action; 1388{ 1389 register int i, pid; 1390 struct passwd *pwd; 1391 1392 for (i = 0; i < 20; i++) { 1393 if ((pid = fork()) < 0) { 1394 sleep((unsigned)(i*i)); 1395 continue; 1396 } 1397 /* 1398 * Child should run as daemon instead of root 1399 */ 1400 if (pid == 0) { 1401 if ((pwd = getpwuid(pp->daemon_user)) == NULL) { 1402 syslog(LOG_ERR, "Can't lookup default daemon uid (%ld) in password file", 1403 pp->daemon_user); 1404 break; 1405 } 1406 initgroups(pwd->pw_name, pwd->pw_gid); 1407 setgid(pwd->pw_gid); 1408 setuid(pp->daemon_user); 1409 } 1410 return(pid); 1411 } 1412 syslog(LOG_ERR, "can't fork"); 1413 1414 switch (action) { 1415 case DORETURN: 1416 return (-1); 1417 default: 1418 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1419 /*FALL THRU*/ 1420 case DOABORT: 1421 exit(1); 1422 } 1423 /*NOTREACHED*/ 1424} 1425 1426/* 1427 * Kill child processes to abort current job. 1428 */ 1429static void 1430abortpr(signo) 1431 int signo; 1432{ 1433 1434 (void) unlink(tempstderr); 1435 kill(0, SIGINT); 1436 if (ofilter > 0) 1437 kill(ofilter, SIGCONT); 1438 while (wait(NULL) > 0) 1439 ; 1440 if (ofilter > 0 && tfd != -1) 1441 unlink(tfile); 1442 exit(0); 1443} 1444 1445static void 1446init(pp) 1447 struct printer *pp; 1448{ 1449 char *s; 1450 1451 sprintf(&width[2], "%ld", pp->page_width); 1452 sprintf(&length[2], "%ld", pp->page_length); 1453 sprintf(&pxwidth[2], "%ld", pp->page_pwidth); 1454 sprintf(&pxlength[2], "%ld", pp->page_plength); 1455 if ((s = checkremote(pp)) != 0) { 1456 syslog(LOG_WARNING, "%s", s); 1457 free(s); 1458 } 1459} 1460 1461void 1462startprinting(printer) 1463 const char *printer; 1464{ 1465 struct printer myprinter, *pp = &myprinter; 1466 int status; 1467 1468 init_printer(pp); 1469 status = getprintcap(printer, pp); 1470 switch(status) { 1471 case PCAPERR_OSERR: 1472 syslog(LOG_ERR, "can't open printer description file: %m"); 1473 exit(1); 1474 case PCAPERR_NOTFOUND: 1475 syslog(LOG_ERR, "unknown printer: %s", printer); 1476 exit(1); 1477 case PCAPERR_TCLOOP: 1478 fatal(pp, "potential reference loop detected in printcap file"); 1479 default: 1480 break; 1481 } 1482 printjob(pp); 1483} 1484 1485/* 1486 * Acquire line printer or remote connection. 1487 */ 1488static void 1489openpr(pp) 1490 const struct printer *pp; 1491{ 1492 int p[2]; 1493 char *cp; 1494 1495 if (pp->remote) { 1496 openrem(pp); 1497 } else if (*pp->lp) { 1498 if ((cp = strchr(pp->lp, '@')) != NULL) 1499 opennet(pp); 1500 else 1501 opentty(pp); 1502 } else { 1503 syslog(LOG_ERR, "%s: no line printer device or host name", 1504 pp->printer); 1505 exit(1); 1506 } 1507 1508 /* 1509 * Start up an output filter, if needed. 1510 */ 1511 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) { 1512 pipe(p); 1513 if (pp->remote) { 1514 strcpy(tfile, TFILENAME); 1515 tfd = mkstemp(tfile); 1516 } 1517 if ((ofilter = dofork(pp, DOABORT)) == 0) { /* child */ 1518 dup2(p[0], 0); /* pipe is std in */ 1519 /* tfile/printer is stdout */ 1520 dup2(pp->remote ? tfd : pfd, 1); 1521 closelog(); 1522 closeallfds(3); 1523 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL) 1524 cp = pp->filters[LPF_OUTPUT]; 1525 else 1526 cp++; 1527 execl(pp->filters[LPF_OUTPUT], cp, width, length, 0); 1528 syslog(LOG_ERR, "%s: %s: %m", pp->printer, 1529 pp->filters[LPF_OUTPUT]); 1530 exit(1); 1531 } 1532 (void) close(p[0]); /* close input side */ 1533 ofd = p[1]; /* use pipe for output */ 1534 } else { 1535 ofd = pfd; 1536 ofilter = 0; 1537 } 1538} 1539 1540/* 1541 * Printer connected directly to the network 1542 * or to a terminal server on the net 1543 */ 1544static void 1545opennet(pp) 1546 const struct printer *pp; 1547{ 1548 register int i; 1549 int resp; 1550 u_long port; 1551 char *ep; 1552 void (*savealrm)(int); 1553 1554 port = strtoul(pp->lp, &ep, 0); 1555 if (*ep != '@' || port > 65535) { 1556 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer, 1557 pp->lp); 1558 exit(1); 1559 } 1560 ep++; 1561 1562 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1563 resp = -1; 1564 savealrm = signal(SIGALRM, alarmhandler); 1565 alarm(pp->conn_timeout); 1566 pfd = getport(pp, ep, port); 1567 alarm(0); 1568 (void)signal(SIGALRM, savealrm); 1569 if (pfd < 0 && errno == ECONNREFUSED) 1570 resp = 1; 1571 else if (pfd >= 0) { 1572 /* 1573 * need to delay a bit for rs232 lines 1574 * to stabilize in case printer is 1575 * connected via a terminal server 1576 */ 1577 delay(500); 1578 break; 1579 } 1580 if (i == 1) { 1581 if (resp < 0) 1582 pstatus(pp, "waiting for %s to come up", 1583 pp->lp); 1584 else 1585 pstatus(pp, 1586 "waiting for access to printer on %s", 1587 pp->lp); 1588 } 1589 sleep(i); 1590 } 1591 pstatus(pp, "sending to %s port %d", ep, port); 1592} 1593 1594/* 1595 * Printer is connected to an RS232 port on this host 1596 */ 1597static void 1598opentty(pp) 1599 const struct printer *pp; 1600{ 1601 register int i; 1602 1603 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1604 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY); 1605 if (pfd >= 0) { 1606 delay(500); 1607 break; 1608 } 1609 if (errno == ENOENT) { 1610 syslog(LOG_ERR, "%s: %m", pp->lp); 1611 exit(1); 1612 } 1613 if (i == 1) 1614 pstatus(pp, 1615 "waiting for %s to become ready (offline?)", 1616 pp->printer); 1617 sleep(i); 1618 } 1619 if (isatty(pfd)) 1620 setty(pp); 1621 pstatus(pp, "%s is ready and printing", pp->printer); 1622} 1623 1624/* 1625 * Printer is on a remote host 1626 */ 1627static void 1628openrem(pp) 1629 const struct printer *pp; 1630{ 1631 register int i; 1632 int resp; 1633 void (*savealrm)(int); 1634 1635 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1636 resp = -1; 1637 savealrm = signal(SIGALRM, alarmhandler); 1638 alarm(pp->conn_timeout); 1639 pfd = getport(pp, pp->remote_host, 0); 1640 alarm(0); 1641 (void)signal(SIGALRM, savealrm); 1642 if (pfd >= 0) { 1643 if ((writel(pfd, "\2", pp->remote_queue, "\n", 1644 (char *)0) 1645 == 2 + strlen(pp->remote_queue)) 1646 && (resp = response(pp)) == 0) 1647 break; 1648 (void) close(pfd); 1649 } 1650 if (i == 1) { 1651 if (resp < 0) 1652 pstatus(pp, "waiting for %s to come up", 1653 pp->remote_host); 1654 else { 1655 pstatus(pp, 1656 "waiting for queue to be enabled on %s", 1657 pp->remote_host); 1658 i = 256; 1659 } 1660 } 1661 sleep(i); 1662 } 1663 pstatus(pp, "sending to %s", pp->remote_host); 1664} 1665 1666/* 1667 * setup tty lines. 1668 */ 1669static void 1670setty(pp) 1671 const struct printer *pp; 1672{ 1673 struct termios ttybuf; 1674 1675 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1676 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer); 1677 exit(1); 1678 } 1679 if (tcgetattr(pfd, &ttybuf) < 0) { 1680 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer); 1681 exit(1); 1682 } 1683 if (pp->baud_rate > 0) 1684 cfsetspeed(&ttybuf, pp->baud_rate); 1685 if (pp->mode_set) { 1686 char *s = strdup(pp->mode_set), *tmp; 1687 1688 while ((tmp = strsep(&s, ",")) != NULL) { 1689 (void) msearch(tmp, &ttybuf); 1690 } 1691 } 1692 if (pp->mode_set != 0 || pp->baud_rate > 0) { 1693 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) { 1694 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer); 1695 } 1696 } 1697} 1698 1699#ifdef __STDC__ 1700#include <stdarg.h> 1701#else 1702#include <varargs.h> 1703#endif 1704 1705static void 1706#ifdef __STDC__ 1707pstatus(const struct printer *pp, const char *msg, ...) 1708#else 1709pstatus(pp, msg, va_alist) 1710 const struct printer *pp; 1711 char *msg; 1712 va_dcl 1713#endif 1714{ 1715 int fd; 1716 char *buf; 1717 va_list ap; 1718#ifdef __STDC__ 1719 va_start(ap, msg); 1720#else 1721 va_start(ap); 1722#endif 1723 1724 umask(0); 1725 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1726 if (fd < 0) { 1727 syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file); 1728 exit(1); 1729 } 1730 ftruncate(fd, 0); 1731 vasprintf(&buf, msg, ap); 1732 va_end(ap); 1733 writel(fd, buf, "\n", (char *)0); 1734 close(fd); 1735 free(buf); 1736} 1737 1738void 1739alarmhandler(signo) 1740{ 1741 /* ignored */ 1742} 1743