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