printjob.c revision 1553
1280405Srpaulo/* 2280405Srpaulo * Copyright (c) 1983, 1993 3280405Srpaulo * The Regents of the University of California. All rights reserved. 4280405Srpaulo * 5280405Srpaulo * 6326344Simp * Redistribution and use in source and binary forms, with or without 7280405Srpaulo * modification, are permitted provided that the following conditions 8280405Srpaulo * are met: 9280405Srpaulo * 1. Redistributions of source code must retain the above copyright 10326344Simp * notice, this list of conditions and the following disclaimer. 11326344Simp * 2. Redistributions in binary form must reproduce the above copyright 12326344Simp * notice, this list of conditions and the following disclaimer in the 13344220Skevans * documentation and/or other materials provided with the distribution. 14326344Simp * 3. All advertising materials mentioning features or use of this software 15326344Simp * must display the following acknowledgement: 16326344Simp * This product includes software developed by the University of 17280405Srpaulo * California, Berkeley and its contributors. 18280405Srpaulo * 4. Neither the name of the University nor the names of its contributors 19280405Srpaulo * may be used to endorse or promote products derived from this software 20326344Simp * without specific prior written permission. 21280405Srpaulo * 22280405Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23280405Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24326344Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25280405Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26280405Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27326344Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28326344Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29280405Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30280405Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31326344Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32326344Simp * SUCH DAMAGE. 33280405Srpaulo */ 34280405Srpaulo 35326344Simp#ifndef lint 36326344Simpstatic char copyright[] = 37326344Simp"@(#) Copyright (c) 1983, 1993\n\ 38280405Srpaulo The Regents of the University of California. All rights reserved.\n"; 39280405Srpaulo#endif /* not lint */ 40326344Simp 41280405Srpaulo#ifndef lint 42280405Srpaulostatic char sccsid[] = "@(#)printjob.c 8.2 (Berkeley) 4/16/94"; 43280405Srpaulo#endif /* not lint */ 44326344Simp 45326344Simp 46280405Srpaulo/* 47280405Srpaulo * printjob -- print jobs in the queue. 48280405Srpaulo * 49326344Simp * NOTE: the lock file is used to pass information to lpq and lprm. 50280405Srpaulo * it does not need to be removed because file locks are dynamic. 51326344Simp */ 52280405Srpaulo 53280405Srpaulo#include <sys/param.h> 54280405Srpaulo#include <sys/wait.h> 55280405Srpaulo#include <sys/stat.h> 56280405Srpaulo#include <sys/types.h> 57280405Srpaulo 58326344Simp#include <pwd.h> 59326344Simp#include <unistd.h> 60280405Srpaulo#include <signal.h> 61280405Srpaulo#include <sgtty.h> 62326344Simp#include <syslog.h> 63326344Simp#include <fcntl.h> 64280405Srpaulo#include <dirent.h> 65280405Srpaulo#include <errno.h> 66326344Simp#include <stdio.h> 67326344Simp#include <string.h> 68326344Simp#include <stdlib.h> 69326344Simp#include "lp.h" 70280405Srpaulo#include "lp.local.h" 71280405Srpaulo#include "pathnames.h" 72280405Srpaulo#include "extern.h" 73326344Simp 74326344Simp#define DORETURN 0 /* absorb fork error */ 75280405Srpaulo#define DOABORT 1 /* abort if dofork fails */ 76280405Srpaulo 77326344Simp/* 78280405Srpaulo * Error tokens 79280405Srpaulo */ 80326344Simp#define REPRINT -2 81326344Simp#define ERROR -1 82326344Simp#define OK 0 83326344Simp#define FATALERR 1 84326344Simp#define NOACCT 2 85326344Simp#define FILTERERR 3 86326344Simp#define ACCESS 4 87326344Simp 88326344Simpstatic dev_t fdev; /* device of file pointed to by symlink */ 89326344Simpstatic ino_t fino; /* inode of file pointed to by symlink */ 90326344Simpstatic FILE *cfp; /* control file */ 91326344Simpstatic int child; /* id of any filters */ 92280405Srpaulostatic int lfd; /* lock file descriptor */ 93280405Srpaulostatic int ofd; /* output filter file descriptor */ 94280405Srpaulostatic int ofilter; /* id of output filter, if any */ 95326344Simpstatic int pfd; /* prstatic inter file descriptor */ 96280405Srpaulostatic int pid; /* pid of lpd process */ 97280405Srpaulostatic int prchild; /* id of pr process */ 98280405Srpaulostatic int remote; /* true if sending files to remote */ 99280405Srpaulostatic char title[80]; /* ``pr'' title */ 100280405Srpaulostatic int tof; /* true if at top of form */ 101280405Srpaulo 102280405Srpaulostatic char class[32]; /* classification field */ 103280405Srpaulostatic char fromhost[32]; /* user's host machine */ 104280405Srpaulo /* indentation size in static characters */ 105280405Srpaulostatic char indent[10] = "-i0"; 106280405Srpaulostatic char jobname[100]; /* job or file name */ 107280405Srpaulostatic char length[10] = "-l"; /* page length in lines */ 108280405Srpaulostatic char logname[32]; /* user's login name */ 109280405Srpaulostatic char pxlength[10] = "-y"; /* page length in pixels */ 110280405Srpaulostatic char pxwidth[10] = "-x"; /* page width in pixels */ 111280405Srpaulostatic char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 112280405Srpaulostatic char width[10] = "-w"; /* page width in static characters */ 113326344Simp 114344220Skevansstatic void abortpr __P((int)); 115326344Simpstatic void banner __P((char *, char *)); 116326344Simpstatic int dofork __P((int)); 117326344Simpstatic int dropit __P((int)); 118326344Simpstatic void init __P((void)); 119326344Simpstatic void openpr __P((void)); 120344220Skevansstatic int print __P((int, char *)); 121344220Skevansstatic int printit __P((char *)); 122344220Skevansstatic void pstatus __P((const char *, ...)); 123344220Skevansstatic char response __P((void)); 124344220Skevansstatic void scan_out __P((int, char *, int)); 125344220Skevansstatic char *scnline __P((int, char *, int)); 126344220Skevansstatic int sendfile __P((int, char *)); 127344220Skevansstatic int sendit __P((char *)); 128344220Skevansstatic void sendmail __P((char *, int)); 129326344Simpstatic void setty __P((void)); 130326344Simp 131326344Simpvoid 132326344Simpprintjob() 133326344Simp{ 134326344Simp struct stat stb; 135326344Simp register struct queue *q, **qp; 136326344Simp struct queue **queue; 137326344Simp register int i, nitems; 138326344Simp long pidoff; 139326344Simp int count = 0; 140326344Simp 141326344Simp init(); /* set up capabilities */ 142326344Simp (void) write(1, "", 1); /* ack that daemon is started */ 143326344Simp (void) close(2); /* set up log file */ 144326344Simp if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 145326344Simp syslog(LOG_ERR, "%s: %m", LF); 146326344Simp (void) open(_PATH_DEVNULL, O_WRONLY); 147326344Simp } 148326344Simp setgid(getegid()); 149326344Simp pid = getpid(); /* for use with lprm */ 150326344Simp setpgrp(0, pid); 151326344Simp signal(SIGHUP, abortpr); 152326344Simp signal(SIGINT, abortpr); 153326344Simp signal(SIGQUIT, abortpr); 154326344Simp signal(SIGTERM, abortpr); 155344220Skevans 156344220Skevans (void) mktemp(tempfile); 157344220Skevans 158344220Skevans /* 159326344Simp * uses short form file names 160326344Simp */ 161326344Simp if (chdir(SD) < 0) { 162 syslog(LOG_ERR, "%s: %m", SD); 163 exit(1); 164 } 165 if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 166 exit(0); /* printing disabled */ 167 lfd = open(LO, O_WRONLY|O_CREAT, 0644); 168 if (lfd < 0) { 169 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 170 exit(1); 171 } 172 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 173 if (errno == EWOULDBLOCK) /* active deamon present */ 174 exit(0); 175 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 176 exit(1); 177 } 178 ftruncate(lfd, 0); 179 /* 180 * write process id for others to know 181 */ 182 sprintf(line, "%u\n", pid); 183 pidoff = i = strlen(line); 184 if (write(lfd, line, i) != i) { 185 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 186 exit(1); 187 } 188 /* 189 * search the spool directory for work and sort by queue order. 190 */ 191 if ((nitems = getq(&queue)) < 0) { 192 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 193 exit(1); 194 } 195 if (nitems == 0) /* no work to do */ 196 exit(0); 197 if (stb.st_mode & 01) { /* reset queue flag */ 198 if (fchmod(lfd, stb.st_mode & 0776) < 0) 199 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 200 } 201 openpr(); /* open printer or remote */ 202again: 203 /* 204 * we found something to do now do it -- 205 * write the name of the current control file into the lock file 206 * so the spool queue program can tell what we're working on 207 */ 208 for (qp = queue; nitems--; free((char *) q)) { 209 q = *qp++; 210 if (stat(q->q_name, &stb) < 0) 211 continue; 212 restart: 213 (void) lseek(lfd, (off_t)pidoff, 0); 214 (void) sprintf(line, "%s\n", q->q_name); 215 i = strlen(line); 216 if (write(lfd, line, i) != i) 217 syslog(LOG_ERR, "%s: %s: %m", printer, LO); 218 if (!remote) 219 i = printit(q->q_name); 220 else 221 i = sendit(q->q_name); 222 /* 223 * Check to see if we are supposed to stop printing or 224 * if we are to rebuild the queue. 225 */ 226 if (fstat(lfd, &stb) == 0) { 227 /* stop printing before starting next job? */ 228 if (stb.st_mode & 0100) 229 goto done; 230 /* rebuild queue (after lpc topq) */ 231 if (stb.st_mode & 01) { 232 for (free((char *) q); nitems--; free((char *) q)) 233 q = *qp++; 234 if (fchmod(lfd, stb.st_mode & 0776) < 0) 235 syslog(LOG_WARNING, "%s: %s: %m", 236 printer, LO); 237 break; 238 } 239 } 240 if (i == OK) /* file ok and printed */ 241 count++; 242 else if (i == REPRINT) { /* try reprinting the job */ 243 syslog(LOG_INFO, "restarting %s", printer); 244 if (ofilter > 0) { 245 kill(ofilter, SIGCONT); /* to be sure */ 246 (void) close(ofd); 247 while ((i = wait(0)) > 0 && i != ofilter) 248 ; 249 ofilter = 0; 250 } 251 (void) close(pfd); /* close printer */ 252 if (ftruncate(lfd, pidoff) < 0) 253 syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 254 openpr(); /* try to reopen printer */ 255 goto restart; 256 } 257 } 258 free((char *) queue); 259 /* 260 * search the spool directory for more work. 261 */ 262 if ((nitems = getq(&queue)) < 0) { 263 syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 264 exit(1); 265 } 266 if (nitems == 0) { /* no more work to do */ 267 done: 268 if (count > 0) { /* Files actually printed */ 269 if (!SF && !tof) 270 (void) write(ofd, FF, strlen(FF)); 271 if (TR != NULL) /* output trailer */ 272 (void) write(ofd, TR, strlen(TR)); 273 } 274 (void) unlink(tempfile); 275 exit(0); 276 } 277 goto again; 278} 279 280char fonts[4][50]; /* fonts for troff */ 281 282char ifonts[4][40] = { 283 _PATH_VFONTR, 284 _PATH_VFONTI, 285 _PATH_VFONTB, 286 _PATH_VFONTS, 287}; 288 289/* 290 * The remaining part is the reading of the control file (cf) 291 * and performing the various actions. 292 */ 293static int 294printit(file) 295 char *file; 296{ 297 register int i; 298 char *cp; 299 int bombed = OK; 300 301 /* 302 * open control file; ignore if no longer there. 303 */ 304 if ((cfp = fopen(file, "r")) == NULL) { 305 syslog(LOG_INFO, "%s: %s: %m", printer, file); 306 return(OK); 307 } 308 /* 309 * Reset troff fonts. 310 */ 311 for (i = 0; i < 4; i++) 312 strcpy(fonts[i], ifonts[i]); 313 sprintf(&width[2], "%d", PW); 314 strcpy(indent+2, "0"); 315 316 /* 317 * read the control file for work to do 318 * 319 * file format -- first character in the line is a command 320 * rest of the line is the argument. 321 * valid commands are: 322 * 323 * S -- "stat info" for symbolic link protection 324 * J -- "job name" on banner page 325 * C -- "class name" on banner page 326 * L -- "literal" user's name to print on banner 327 * T -- "title" for pr 328 * H -- "host name" of machine where lpr was done 329 * P -- "person" user's login name 330 * I -- "indent" amount to indent output 331 * f -- "file name" name of text file to print 332 * l -- "file name" text file with control chars 333 * p -- "file name" text file to print with pr(1) 334 * t -- "file name" troff(1) file to print 335 * n -- "file name" ditroff(1) file to print 336 * d -- "file name" dvi file to print 337 * g -- "file name" plot(1G) file to print 338 * v -- "file name" plain raster file to print 339 * c -- "file name" cifplot file to print 340 * 1 -- "R font file" for troff 341 * 2 -- "I font file" for troff 342 * 3 -- "B font file" for troff 343 * 4 -- "S font file" for troff 344 * N -- "name" of file (used by lpq) 345 * U -- "unlink" name of file to remove 346 * (after we print it. (Pass 2 only)). 347 * M -- "mail" to user when done printing 348 * 349 * getline reads a line and expands tabs to blanks 350 */ 351 352 /* pass 1 */ 353 354 while (getline(cfp)) 355 switch (line[0]) { 356 case 'H': 357 strcpy(fromhost, line+1); 358 if (class[0] == '\0') 359 strncpy(class, line+1, sizeof(class)-1); 360 continue; 361 362 case 'P': 363 strncpy(logname, line+1, sizeof(logname)-1); 364 if (RS) { /* restricted */ 365 if (getpwnam(logname) == NULL) { 366 bombed = NOACCT; 367 sendmail(line+1, bombed); 368 goto pass2; 369 } 370 } 371 continue; 372 373 case 'S': 374 cp = line+1; 375 i = 0; 376 while (*cp >= '0' && *cp <= '9') 377 i = i * 10 + (*cp++ - '0'); 378 fdev = i; 379 cp++; 380 i = 0; 381 while (*cp >= '0' && *cp <= '9') 382 i = i * 10 + (*cp++ - '0'); 383 fino = i; 384 continue; 385 386 case 'J': 387 if (line[1] != '\0') 388 strncpy(jobname, line+1, sizeof(jobname)-1); 389 else 390 strcpy(jobname, " "); 391 continue; 392 393 case 'C': 394 if (line[1] != '\0') 395 strncpy(class, line+1, sizeof(class)-1); 396 else if (class[0] == '\0') 397 gethostname(class, sizeof(class)); 398 continue; 399 400 case 'T': /* header title for pr */ 401 strncpy(title, line+1, sizeof(title)-1); 402 continue; 403 404 case 'L': /* identification line */ 405 if (!SH && !HL) 406 banner(line+1, jobname); 407 continue; 408 409 case '1': /* troff fonts */ 410 case '2': 411 case '3': 412 case '4': 413 if (line[1] != '\0') 414 strcpy(fonts[line[0]-'1'], line+1); 415 continue; 416 417 case 'W': /* page width */ 418 strncpy(width+2, line+1, sizeof(width)-3); 419 continue; 420 421 case 'I': /* indent amount */ 422 strncpy(indent+2, line+1, sizeof(indent)-3); 423 continue; 424 425 default: /* some file to print */ 426 switch (i = print(line[0], line+1)) { 427 case ERROR: 428 if (bombed == OK) 429 bombed = FATALERR; 430 break; 431 case REPRINT: 432 (void) fclose(cfp); 433 return(REPRINT); 434 case FILTERERR: 435 case ACCESS: 436 bombed = i; 437 sendmail(logname, bombed); 438 } 439 title[0] = '\0'; 440 continue; 441 442 case 'N': 443 case 'U': 444 case 'M': 445 continue; 446 } 447 448 /* pass 2 */ 449 450pass2: 451 fseek(cfp, 0L, 0); 452 while (getline(cfp)) 453 switch (line[0]) { 454 case 'L': /* identification line */ 455 if (!SH && HL) 456 banner(line+1, jobname); 457 continue; 458 459 case 'M': 460 if (bombed < NOACCT) /* already sent if >= NOACCT */ 461 sendmail(line+1, bombed); 462 continue; 463 464 case 'U': 465 (void) unlink(line+1); 466 } 467 /* 468 * clean-up in case another control file exists 469 */ 470 (void) fclose(cfp); 471 (void) unlink(file); 472 return(bombed == OK ? OK : ERROR); 473} 474 475/* 476 * Print a file. 477 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 478 * Return -1 if a non-recoverable error occured, 479 * 2 if the filter detected some errors (but printed the job anyway), 480 * 1 if we should try to reprint this job and 481 * 0 if all is well. 482 * Note: all filters take stdin as the file, stdout as the printer, 483 * stderr as the log file, and must not ignore SIGINT. 484 */ 485static int 486print(format, file) 487 int format; 488 char *file; 489{ 490 register int n; 491 register char *prog; 492 int fi, fo; 493 FILE *fp; 494 char *av[15], buf[BUFSIZ]; 495 int pid, p[2], stopped = 0; 496 union wait status; 497 struct stat stb; 498 499 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 500 return(ERROR); 501 /* 502 * Check to see if data file is a symbolic link. If so, it should 503 * still point to the same file or someone is trying to print 504 * something he shouldn't. 505 */ 506 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 && 507 (stb.st_dev != fdev || stb.st_ino != fino)) 508 return(ACCESS); 509 if (!SF && !tof) { /* start on a fresh page */ 510 (void) write(ofd, FF, strlen(FF)); 511 tof = 1; 512 } 513 if (IF == NULL && (format == 'f' || format == 'l')) { 514 tof = 0; 515 while ((n = read(fi, buf, BUFSIZ)) > 0) 516 if (write(ofd, buf, n) != n) { 517 (void) close(fi); 518 return(REPRINT); 519 } 520 (void) close(fi); 521 return(OK); 522 } 523 switch (format) { 524 case 'p': /* print file using 'pr' */ 525 if (IF == NULL) { /* use output filter */ 526 prog = _PATH_PR; 527 av[0] = "pr"; 528 av[1] = width; 529 av[2] = length; 530 av[3] = "-h"; 531 av[4] = *title ? title : " "; 532 av[5] = 0; 533 fo = ofd; 534 goto start; 535 } 536 pipe(p); 537 if ((prchild = dofork(DORETURN)) == 0) { /* child */ 538 dup2(fi, 0); /* file is stdin */ 539 dup2(p[1], 1); /* pipe is stdout */ 540 for (n = 3; n < NOFILE; n++) 541 (void) close(n); 542 execl(_PATH_PR, "pr", width, length, 543 "-h", *title ? title : " ", 0); 544 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 545 exit(2); 546 } 547 (void) close(p[1]); /* close output side */ 548 (void) close(fi); 549 if (prchild < 0) { 550 prchild = 0; 551 (void) close(p[0]); 552 return(ERROR); 553 } 554 fi = p[0]; /* use pipe for input */ 555 case 'f': /* print plain text file */ 556 prog = IF; 557 av[1] = width; 558 av[2] = length; 559 av[3] = indent; 560 n = 4; 561 break; 562 case 'l': /* like 'f' but pass control characters */ 563 prog = IF; 564 av[1] = "-c"; 565 av[2] = width; 566 av[3] = length; 567 av[4] = indent; 568 n = 5; 569 break; 570 case 'r': /* print a fortran text file */ 571 prog = RF; 572 av[1] = width; 573 av[2] = length; 574 n = 3; 575 break; 576 case 't': /* print troff output */ 577 case 'n': /* print ditroff output */ 578 case 'd': /* print tex output */ 579 (void) unlink(".railmag"); 580 if ((fo = creat(".railmag", FILMOD)) < 0) { 581 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 582 (void) unlink(".railmag"); 583 } else { 584 for (n = 0; n < 4; n++) { 585 if (fonts[n][0] != '/') 586 (void) write(fo, _PATH_VFONT, 587 sizeof(_PATH_VFONT) - 1); 588 (void) write(fo, fonts[n], strlen(fonts[n])); 589 (void) write(fo, "\n", 1); 590 } 591 (void) close(fo); 592 } 593 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 594 av[1] = pxwidth; 595 av[2] = pxlength; 596 n = 3; 597 break; 598 case 'c': /* print cifplot output */ 599 prog = CF; 600 av[1] = pxwidth; 601 av[2] = pxlength; 602 n = 3; 603 break; 604 case 'g': /* print plot(1G) output */ 605 prog = GF; 606 av[1] = pxwidth; 607 av[2] = pxlength; 608 n = 3; 609 break; 610 case 'v': /* print raster output */ 611 prog = VF; 612 av[1] = pxwidth; 613 av[2] = pxlength; 614 n = 3; 615 break; 616 default: 617 (void) close(fi); 618 syslog(LOG_ERR, "%s: illegal format character '%c'", 619 printer, format); 620 return(ERROR); 621 } 622 if ((av[0] = rindex(prog, '/')) != NULL) 623 av[0]++; 624 else 625 av[0] = prog; 626 av[n++] = "-n"; 627 av[n++] = logname; 628 av[n++] = "-h"; 629 av[n++] = fromhost; 630 av[n++] = AF; 631 av[n] = 0; 632 fo = pfd; 633 if (ofilter > 0) { /* stop output filter */ 634 write(ofd, "\031\1", 2); 635 while ((pid = 636 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 637 ; 638 if (status.w_stopval != WSTOPPED) { 639 (void) close(fi); 640 syslog(LOG_WARNING, "%s: output filter died (%d)", 641 printer, status.w_retcode); 642 return(REPRINT); 643 } 644 stopped++; 645 } 646start: 647 if ((child = dofork(DORETURN)) == 0) { /* child */ 648 dup2(fi, 0); 649 dup2(fo, 1); 650 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 651 if (n >= 0) 652 dup2(n, 2); 653 for (n = 3; n < NOFILE; n++) 654 (void) close(n); 655 execv(prog, av); 656 syslog(LOG_ERR, "cannot execv %s", prog); 657 exit(2); 658 } 659 (void) close(fi); 660 if (child < 0) 661 status.w_retcode = 100; 662 else 663 while ((pid = wait((int *)&status)) > 0 && pid != child) 664 ; 665 child = 0; 666 prchild = 0; 667 if (stopped) { /* restart output filter */ 668 if (kill(ofilter, SIGCONT) < 0) { 669 syslog(LOG_ERR, "cannot restart output filter"); 670 exit(1); 671 } 672 } 673 tof = 0; 674 675 /* Copy filter output to "lf" logfile */ 676 if (fp = fopen(tempfile, "r")) { 677 while (fgets(buf, sizeof(buf), fp)) 678 fputs(buf, stderr); 679 fclose(fp); 680 } 681 682 if (!WIFEXITED(status)) { 683 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 684 printer, format, status.w_termsig); 685 return(ERROR); 686 } 687 switch (status.w_retcode) { 688 case 0: 689 tof = 1; 690 return(OK); 691 case 1: 692 return(REPRINT); 693 default: 694 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 695 printer, format, status.w_retcode); 696 case 2: 697 return(ERROR); 698 } 699} 700 701/* 702 * Send the daemon control file (cf) and any data files. 703 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 704 * 0 if all is well. 705 */ 706static int 707sendit(file) 708 char *file; 709{ 710 register int i, err = OK; 711 char *cp, last[BUFSIZ]; 712 713 /* 714 * open control file 715 */ 716 if ((cfp = fopen(file, "r")) == NULL) 717 return(OK); 718 /* 719 * read the control file for work to do 720 * 721 * file format -- first character in the line is a command 722 * rest of the line is the argument. 723 * commands of interest are: 724 * 725 * a-z -- "file name" name of file to print 726 * U -- "unlink" name of file to remove 727 * (after we print it. (Pass 2 only)). 728 */ 729 730 /* 731 * pass 1 732 */ 733 while (getline(cfp)) { 734 again: 735 if (line[0] == 'S') { 736 cp = line+1; 737 i = 0; 738 while (*cp >= '0' && *cp <= '9') 739 i = i * 10 + (*cp++ - '0'); 740 fdev = i; 741 cp++; 742 i = 0; 743 while (*cp >= '0' && *cp <= '9') 744 i = i * 10 + (*cp++ - '0'); 745 fino = i; 746 continue; 747 } 748 if (line[0] >= 'a' && line[0] <= 'z') { 749 strcpy(last, line); 750 while (i = getline(cfp)) 751 if (strcmp(last, line)) 752 break; 753 switch (sendfile('\3', last+1)) { 754 case OK: 755 if (i) 756 goto again; 757 break; 758 case REPRINT: 759 (void) fclose(cfp); 760 return(REPRINT); 761 case ACCESS: 762 sendmail(logname, ACCESS); 763 case ERROR: 764 err = ERROR; 765 } 766 break; 767 } 768 } 769 if (err == OK && sendfile('\2', file) > 0) { 770 (void) fclose(cfp); 771 return(REPRINT); 772 } 773 /* 774 * pass 2 775 */ 776 fseek(cfp, 0L, 0); 777 while (getline(cfp)) 778 if (line[0] == 'U') 779 (void) unlink(line+1); 780 /* 781 * clean-up in case another control file exists 782 */ 783 (void) fclose(cfp); 784 (void) unlink(file); 785 return(err); 786} 787 788/* 789 * Send a data file to the remote machine and spool it. 790 * Return positive if we should try resending. 791 */ 792static int 793sendfile(type, file) 794 int type; 795 char *file; 796{ 797 register int f, i, amt; 798 struct stat stb; 799 char buf[BUFSIZ]; 800 int sizerr, resp; 801 802 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 803 return(ERROR); 804 /* 805 * Check to see if data file is a symbolic link. If so, it should 806 * still point to the same file or someone is trying to print something 807 * he shouldn't. 808 */ 809 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 810 (stb.st_dev != fdev || stb.st_ino != fino)) 811 return(ACCESS); 812 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 813 amt = strlen(buf); 814 for (i = 0; ; i++) { 815 if (write(pfd, buf, amt) != amt || 816 (resp = response()) < 0 || resp == '\1') { 817 (void) close(f); 818 return(REPRINT); 819 } else if (resp == '\0') 820 break; 821 if (i == 0) 822 pstatus("no space on remote; waiting for queue to drain"); 823 if (i == 10) 824 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 825 printer, RM); 826 sleep(5 * 60); 827 } 828 if (i) 829 pstatus("sending to %s", RM); 830 sizerr = 0; 831 for (i = 0; i < stb.st_size; i += BUFSIZ) { 832 amt = BUFSIZ; 833 if (i + amt > stb.st_size) 834 amt = stb.st_size - i; 835 if (sizerr == 0 && read(f, buf, amt) != amt) 836 sizerr = 1; 837 if (write(pfd, buf, amt) != amt) { 838 (void) close(f); 839 return(REPRINT); 840 } 841 } 842 843 844 845 846 (void) close(f); 847 if (sizerr) { 848 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 849 /* tell recvjob to ignore this file */ 850 (void) write(pfd, "\1", 1); 851 return(ERROR); 852 } 853 if (write(pfd, "", 1) != 1 || response()) 854 return(REPRINT); 855 return(OK); 856} 857 858/* 859 * Check to make sure there have been no errors and that both programs 860 * are in sync with eachother. 861 * Return non-zero if the connection was lost. 862 */ 863static char 864response() 865{ 866 char resp; 867 868 if (read(pfd, &resp, 1) != 1) { 869 syslog(LOG_INFO, "%s: lost connection", printer); 870 return(-1); 871 } 872 return(resp); 873} 874 875/* 876 * Banner printing stuff 877 */ 878static void 879banner(name1, name2) 880 char *name1, *name2; 881{ 882 time_t tvec; 883 extern char *ctime(); 884 885 time(&tvec); 886 if (!SF && !tof) 887 (void) write(ofd, FF, strlen(FF)); 888 if (SB) { /* short banner only */ 889 if (class[0]) { 890 (void) write(ofd, class, strlen(class)); 891 (void) write(ofd, ":", 1); 892 } 893 (void) write(ofd, name1, strlen(name1)); 894 (void) write(ofd, " Job: ", 7); 895 (void) write(ofd, name2, strlen(name2)); 896 (void) write(ofd, " Date: ", 8); 897 (void) write(ofd, ctime(&tvec), 24); 898 (void) write(ofd, "\n", 1); 899 } else { /* normal banner */ 900 (void) write(ofd, "\n\n\n", 3); 901 scan_out(ofd, name1, '\0'); 902 (void) write(ofd, "\n\n", 2); 903 scan_out(ofd, name2, '\0'); 904 if (class[0]) { 905 (void) write(ofd,"\n\n\n",3); 906 scan_out(ofd, class, '\0'); 907 } 908 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 909 (void) write(ofd, name2, strlen(name2)); 910 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 911 (void) write(ofd, ctime(&tvec), 24); 912 (void) write(ofd, "\n", 1); 913 } 914 if (!SF) 915 (void) write(ofd, FF, strlen(FF)); 916 tof = 1; 917} 918 919static char * 920scnline(key, p, c) 921 register int key; 922 register char *p; 923 int c; 924{ 925 register scnwidth; 926 927 for (scnwidth = WIDTH; --scnwidth;) { 928 key <<= 1; 929 *p++ = key & 0200 ? c : BACKGND; 930 } 931 return (p); 932} 933 934#define TRC(q) (((q)-' ')&0177) 935 936static void 937scan_out(scfd, scsp, dlm) 938 int scfd, dlm; 939 char *scsp; 940{ 941 register char *strp; 942 register nchrs, j; 943 char outbuf[LINELEN+1], *sp, c, cc; 944 int d, scnhgt; 945 extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 946 947 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 948 strp = &outbuf[0]; 949 sp = scsp; 950 for (nchrs = 0; ; ) { 951 d = dropit(c = TRC(cc = *sp++)); 952 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 953 for (j = WIDTH; --j;) 954 *strp++ = BACKGND; 955 else 956 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 957 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 958 break; 959 *strp++ = BACKGND; 960 *strp++ = BACKGND; 961 } 962 while (*--strp == BACKGND && strp >= outbuf) 963 ; 964 strp++; 965 *strp++ = '\n'; 966 (void) write(scfd, outbuf, strp-outbuf); 967 } 968} 969 970static int 971dropit(c) 972 int c; 973{ 974 switch(c) { 975 976 case TRC('_'): 977 case TRC(';'): 978 case TRC(','): 979 case TRC('g'): 980 case TRC('j'): 981 case TRC('p'): 982 case TRC('q'): 983 case TRC('y'): 984 return (DROP); 985 986 default: 987 return (0); 988 } 989} 990 991/* 992 * sendmail --- 993 * tell people about job completion 994 */ 995static void 996sendmail(user, bombed) 997 char *user; 998 int bombed; 999{ 1000 register int i; 1001 int p[2], s; 1002 register char *cp; 1003 char buf[100]; 1004 struct stat stb; 1005 FILE *fp; 1006 1007 pipe(p); 1008 if ((s = dofork(DORETURN)) == 0) { /* child */ 1009 dup2(p[0], 0); 1010 for (i = 3; i < NOFILE; i++) 1011 (void) close(i); 1012 if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 1013 cp++; 1014 else 1015 cp = _PATH_SENDMAIL; 1016 sprintf(buf, "%s@%s", user, fromhost); 1017 execl(_PATH_SENDMAIL, cp, buf, 0); 1018 exit(0); 1019 } else if (s > 0) { /* parent */ 1020 dup2(p[1], 1); 1021 printf("To: %s@%s\n", user, fromhost); 1022 printf("Subject: printer job\n\n"); 1023 printf("Your printer job "); 1024 if (*jobname) 1025 printf("(%s) ", jobname); 1026 switch (bombed) { 1027 case OK: 1028 printf("\ncompleted successfully\n"); 1029 break; 1030 default: 1031 case FATALERR: 1032 printf("\ncould not be printed\n"); 1033 break; 1034 case NOACCT: 1035 printf("\ncould not be printed without an account on %s\n", host); 1036 break; 1037 case FILTERERR: 1038 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1039 (fp = fopen(tempfile, "r")) == NULL) { 1040 printf("\nwas printed but had some errors\n"); 1041 break; 1042 } 1043 printf("\nwas printed but had the following errors:\n"); 1044 while ((i = getc(fp)) != EOF) 1045 putchar(i); 1046 (void) fclose(fp); 1047 break; 1048 case ACCESS: 1049 printf("\nwas not printed because it was not linked to the original file\n"); 1050 } 1051 fflush(stdout); 1052 (void) close(1); 1053 } 1054 (void) close(p[0]); 1055 (void) close(p[1]); 1056 wait(&s); 1057} 1058 1059/* 1060 * dofork - fork with retries on failure 1061 */ 1062static int 1063dofork(action) 1064 int action; 1065{ 1066 register int i, pid; 1067 1068 for (i = 0; i < 20; i++) { 1069 if ((pid = fork()) < 0) { 1070 sleep((unsigned)(i*i)); 1071 continue; 1072 } 1073 /* 1074 * Child should run as daemon instead of root 1075 */ 1076 if (pid == 0) 1077 setuid(DU); 1078 return(pid); 1079 } 1080 syslog(LOG_ERR, "can't fork"); 1081 1082 switch (action) { 1083 case DORETURN: 1084 return (-1); 1085 default: 1086 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1087 /*FALL THRU*/ 1088 case DOABORT: 1089 exit(1); 1090 } 1091 /*NOTREACHED*/ 1092} 1093 1094/* 1095 * Kill child processes to abort current job. 1096 */ 1097static void 1098abortpr(signo) 1099 int signo; 1100{ 1101 (void) unlink(tempfile); 1102 kill(0, SIGINT); 1103 if (ofilter > 0) 1104 kill(ofilter, SIGCONT); 1105 while (wait(NULL) > 0) 1106 ; 1107 exit(0); 1108} 1109 1110static void 1111init() 1112{ 1113 int status; 1114 char *s; 1115 1116 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1117 syslog(LOG_ERR, "can't open printer description file"); 1118 exit(1); 1119 } else if (status == -1) { 1120 syslog(LOG_ERR, "unknown printer: %s", printer); 1121 exit(1); 1122 } else if (status == -3) 1123 fatal("potential reference loop detected in printcap file"); 1124 1125 if (cgetstr(bp, "lp", &LP) == -1) 1126 LP = _PATH_DEFDEVLP; 1127 if (cgetstr(bp, "rp", &RP) == -1) 1128 RP = DEFLP; 1129 if (cgetstr(bp, "lo", &LO) == -1) 1130 LO = DEFLOCK; 1131 if (cgetstr(bp, "st", &ST) == -1) 1132 ST = DEFSTAT; 1133 if (cgetstr(bp, "lf", &LF) == -1) 1134 LF = _PATH_CONSOLE; 1135 if (cgetstr(bp, "sd", &SD) == -1) 1136 SD = _PATH_DEFSPOOL; 1137 if (cgetnum(bp, "du", &DU) < 0) 1138 DU = DEFUID; 1139 if (cgetstr(bp,"ff", &FF) == -1) 1140 FF = DEFFF; 1141 if (cgetnum(bp, "pw", &PW) < 0) 1142 PW = DEFWIDTH; 1143 sprintf(&width[2], "%d", PW); 1144 if (cgetnum(bp, "pl", &PL) < 0) 1145 PL = DEFLENGTH; 1146 sprintf(&length[2], "%d", PL); 1147 if (cgetnum(bp,"px", &PX) < 0) 1148 PX = 0; 1149 sprintf(&pxwidth[2], "%d", PX); 1150 if (cgetnum(bp, "py", &PY) < 0) 1151 PY = 0; 1152 sprintf(&pxlength[2], "%d", PY); 1153 cgetstr(bp, "rm", &RM); 1154 if (s = checkremote()) 1155 syslog(LOG_WARNING, s); 1156 1157 cgetstr(bp, "af", &AF); 1158 cgetstr(bp, "of", &OF); 1159 cgetstr(bp, "if", &IF); 1160 cgetstr(bp, "rf", &RF); 1161 cgetstr(bp, "tf", &TF); 1162 cgetstr(bp, "nf", &NF); 1163 cgetstr(bp, "df", &DF); 1164 cgetstr(bp, "gf", &GF); 1165 cgetstr(bp, "vf", &VF); 1166 cgetstr(bp, "cf", &CF); 1167 cgetstr(bp, "tr", &TR); 1168 1169 RS = (cgetcap(bp, "rs", ':') != NULL); 1170 SF = (cgetcap(bp, "sf", ':') != NULL); 1171 SH = (cgetcap(bp, "sh", ':') != NULL); 1172 SB = (cgetcap(bp, "sb", ':') != NULL); 1173 HL = (cgetcap(bp, "hl", ':') != NULL); 1174 RW = (cgetcap(bp, "rw", ':') != NULL); 1175 1176 cgetnum(bp, "br", &BR); 1177 if (cgetnum(bp, "fc", &FC) < 0) 1178 FC = 0; 1179 if (cgetnum(bp, "fs", &FS) < 0) 1180 FS = 0; 1181 if (cgetnum(bp, "xc", &XC) < 0) 1182 XC = 0; 1183 if (cgetnum(bp, "xs", &XS) < 0) 1184 XS = 0; 1185 1186 tof = (cgetcap(bp, "fo", ':') == NULL); 1187} 1188 1189/* 1190 * Acquire line printer or remote connection. 1191 */ 1192static void 1193openpr() 1194{ 1195 register int i, n; 1196 int resp; 1197 1198 if (!sendtorem && *LP) { 1199 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1200 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1201 if (pfd >= 0) 1202 break; 1203 if (errno == ENOENT) { 1204 syslog(LOG_ERR, "%s: %m", LP); 1205 exit(1); 1206 } 1207 if (i == 1) 1208 pstatus("waiting for %s to become ready (offline ?)", printer); 1209 sleep(i); 1210 } 1211 if (isatty(pfd)) 1212 setty(); 1213 pstatus("%s is ready and printing", printer); 1214 } else if (RM != NULL) { 1215 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1216 resp = -1; 1217 pfd = getport(RM); 1218 if (pfd >= 0) { 1219 (void) sprintf(line, "\2%s\n", RP); 1220 n = strlen(line); 1221 if (write(pfd, line, n) == n && 1222 (resp = response()) == '\0') 1223 break; 1224 (void) close(pfd); 1225 } 1226 if (i == 1) { 1227 if (resp < 0) 1228 pstatus("waiting for %s to come up", RM); 1229 else { 1230 pstatus("waiting for queue to be enabled on %s", RM); 1231 i = 256; 1232 } 1233 } 1234 sleep(i); 1235 } 1236 pstatus("sending to %s", RM); 1237 remote = 1; 1238 } else { 1239 syslog(LOG_ERR, "%s: no line printer device or host name", 1240 printer); 1241 exit(1); 1242 } 1243 /* 1244 * Start up an output filter, if needed. 1245 */ 1246 if (!remote && OF) { 1247 int p[2]; 1248 char *cp; 1249 1250 pipe(p); 1251 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1252 dup2(p[0], 0); /* pipe is std in */ 1253 dup2(pfd, 1); /* printer is std out */ 1254 for (i = 3; i < NOFILE; i++) 1255 (void) close(i); 1256 if ((cp = rindex(OF, '/')) == NULL) 1257 cp = OF; 1258 else 1259 cp++; 1260 execl(OF, cp, width, length, 0); 1261 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1262 exit(1); 1263 } 1264 (void) close(p[0]); /* close input side */ 1265 ofd = p[1]; /* use pipe for output */ 1266 } else { 1267 ofd = pfd; 1268 ofilter = 0; 1269 } 1270} 1271 1272struct bauds { 1273 int baud; 1274 int speed; 1275} bauds[] = { 1276 50, B50, 1277 75, B75, 1278 110, B110, 1279 134, B134, 1280 150, B150, 1281 200, B200, 1282 300, B300, 1283 600, B600, 1284 1200, B1200, 1285 1800, B1800, 1286 2400, B2400, 1287 4800, B4800, 1288 9600, B9600, 1289 19200, EXTA, 1290 38400, EXTB, 1291 0, 0 1292}; 1293 1294/* 1295 * setup tty lines. 1296 */ 1297static void 1298setty() 1299{ 1300 struct sgttyb ttybuf; 1301 register struct bauds *bp; 1302 1303 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1304 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1305 exit(1); 1306 } 1307 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1308 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1309 exit(1); 1310 } 1311 if (BR > 0) { 1312 for (bp = bauds; bp->baud; bp++) 1313 if (BR == bp->baud) 1314 break; 1315 if (!bp->baud) { 1316 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1317 exit(1); 1318 } 1319 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1320 } 1321 ttybuf.sg_flags &= ~FC; 1322 ttybuf.sg_flags |= FS; 1323 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1324 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1325 exit(1); 1326 } 1327 if (XC) { 1328 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1329 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1330 exit(1); 1331 } 1332 } 1333 if (XS) { 1334 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1335 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1336 exit(1); 1337 } 1338 } 1339} 1340 1341#if __STDC__ 1342#include <stdarg.h> 1343#else 1344#include <varargs.h> 1345#endif 1346 1347void 1348#if __STDC__ 1349pstatus(const char *msg, ...) 1350#else 1351pstatus(msg, va_alist) 1352 char *msg; 1353 va_dcl 1354#endif 1355{ 1356 register int fd; 1357 char buf[BUFSIZ]; 1358 va_list ap; 1359#if __STDC__ 1360 va_start(ap, msg); 1361#else 1362 va_start(ap); 1363#endif 1364 1365 umask(0); 1366 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1367 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1368 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1369 exit(1); 1370 } 1371 ftruncate(fd, 0); 1372 (void)vsnprintf(buf, sizeof(buf), msg, ap); 1373 va_end(ap); 1374 strcat(buf, "\n"); 1375 (void) write(fd, buf, strlen(buf)); 1376 (void) close(fd); 1377} 1378