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