printjob.c revision 5445
11573Srgrimes/* 21573Srgrimes * Copyright (c) 1983, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * 61573Srgrimes * Redistribution and use in source and binary forms, with or without 71573Srgrimes * modification, are permitted provided that the following conditions 81573Srgrimes * are met: 91573Srgrimes * 1. Redistributions of source code must retain the above copyright 101573Srgrimes * notice, this list of conditions and the following disclaimer. 111573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer in the 131573Srgrimes * documentation and/or other materials provided with the distribution. 141573Srgrimes * 3. All advertising materials mentioning features or use of this software 151573Srgrimes * must display the following acknowledgement: 16251672Semaste * This product includes software developed by the University of 171573Srgrimes * California, Berkeley and its contributors. 181573Srgrimes * 4. Neither the name of the University nor the names of its contributors 191573Srgrimes * may be used to endorse or promote products derived from this software 201573Srgrimes * without specific prior written permission. 211573Srgrimes * 221573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321573Srgrimes * SUCH DAMAGE. 3350476Speter */ 341573Srgrimes 3587738Sru#ifndef lint 361573Srgrimesstatic char copyright[] = 371573Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 381573Srgrimes The Regents of the University of California. All rights reserved.\n"; 3987027Sfenner#endif /* not lint */ 4087738Sru 4187738Sru#ifndef lint 4287738Srustatic char sccsid[] = "@(#)printjob.c 8.2 (Berkeley) 4/16/94"; 4389585Syar#endif /* not lint */ 4487738Sru 4559460Sphantom 4659460Sphantom/* 471573Srgrimes * printjob -- print jobs in the queue. 4883206Sasmodai * 4983206Sasmodai * NOTE: the lock file is used to pass information to lpq and lprm. 5087738Sru * it does not need to be removed because file locks are dynamic. 51103012Stjr */ 5287738Sru 53103012Stjr#include <sys/param.h> 5487027Sfenner#include <sys/wait.h> 5587027Sfenner#include <sys/stat.h> 56103012Stjr#include <sys/types.h> 5783206Sasmodai 5883206Sasmodai#include <pwd.h> 5983206Sasmodai#include <unistd.h> 601573Srgrimes#include <signal.h> 611573Srgrimes#include <sgtty.h> 621573Srgrimes#include <syslog.h> 631573Srgrimes#include <fcntl.h> 641573Srgrimes#include <dirent.h> 651573Srgrimes#include <errno.h> 661573Srgrimes#include <stdio.h> 671573Srgrimes#include <string.h> 681573Srgrimes#include <stdlib.h> 6987738Sru#include "lp.h" 701573Srgrimes#include "lp.local.h" 711573Srgrimes#include "pathnames.h" 7273152Sobrien#include "extern.h" 7373152Sobrien 7473152Sobrien#define DORETURN 0 /* absorb fork error */ 7573152Sobrien#define DOABORT 1 /* abort if dofork fails */ 7673152Sobrien 7787738Sru/* 7873152Sobrien * Error tokens 7973152Sobrien */ 8087027Sfenner#define REPRINT -2 8187027Sfenner#define ERROR -1 8287027Sfenner#define OK 0 8387027Sfenner#define FATALERR 1 8487027Sfenner#define NOACCT 2 8587738Sru#define FILTERERR 3 8687027Sfenner#define ACCESS 4 8787027Sfenner 881573Srgrimesstatic dev_t fdev; /* device of file pointed to by symlink */ 891573Srgrimesstatic ino_t fino; /* inode of file pointed to by symlink */ 901573Srgrimesstatic FILE *cfp; /* control file */ 911573Srgrimesstatic int child; /* id of any filters */ 921573Srgrimesstatic int lfd; /* lock file descriptor */ 9387738Srustatic int ofd; /* output filter file descriptor */ 941573Srgrimesstatic int ofilter; /* id of output filter, if any */ 951573Srgrimesstatic int pfd; /* prstatic inter file descriptor */ 961573Srgrimesstatic int pid; /* pid of lpd process */ 971573Srgrimesstatic int prchild; /* id of pr process */ 981573Srgrimesstatic int remote; /* true if sending files to remote */ 991573Srgrimesstatic char title[80]; /* ``pr'' title */ 1001573Srgrimesstatic int tof; /* true if at top of form */ 1011573Srgrimes 1021573Srgrimesstatic char class[32]; /* classification field */ 1031573Srgrimesstatic char fromhost[32]; /* user's host machine */ 1041573Srgrimes /* indentation size in static characters */ 1051573Srgrimesstatic char indent[10] = "-i0"; 1061573Srgrimesstatic char jobname[100]; /* job or file name */ 1071573Srgrimesstatic char length[10] = "-l"; /* page length in lines */ 1081573Srgrimesstatic char logname[32]; /* user's login name */ 1091573Srgrimesstatic char pxlength[10] = "-y"; /* page length in pixels */ 1101573Srgrimesstatic char pxwidth[10] = "-x"; /* page width in pixels */ 1111573Srgrimesstatic char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 11287738Srustatic char width[10] = "-w"; /* page width in static characters */ 1131573Srgrimes 1141573Srgrimesstatic void abortpr __P((int)); 1151573Srgrimesstatic void banner __P((char *, char *)); 1161573Srgrimesstatic int dofork __P((int)); 1171573Srgrimesstatic int dropit __P((int)); 1181573Srgrimesstatic void init __P((void)); 1191573Srgrimesstatic void openpr __P((void)); 1201573Srgrimesstatic int print __P((int, char *)); 12187738Srustatic int printit __P((char *)); 1221573Srgrimesstatic void pstatus __P((const char *, ...)); 1231573Srgrimesstatic char response __P((void)); 1241573Srgrimesstatic void scan_out __P((int, char *, int)); 1251573Srgrimesstatic char *scnline __P((int, char *, int)); 1261573Srgrimesstatic int sendfile __P((int, char *)); 1271573Srgrimesstatic int sendit __P((char *)); 1281573Srgrimesstatic void sendmail __P((char *, int)); 1291573Srgrimesstatic void setty __P((void)); 1301573Srgrimes 1311573Srgrimesvoid 1321573Srgrimesprintjob() 1331573Srgrimes{ 1341573Srgrimes struct stat stb; 1351573Srgrimes register struct queue *q, **qp; 1361573Srgrimes struct queue **queue; 13787738Sru register int i, nitems; 13887738Sru long pidoff; 1391573Srgrimes int count = 0; 1401573Srgrimes 1411573Srgrimes init(); /* set up capabilities */ 1421573Srgrimes (void) write(1, "", 1); /* ack that daemon is started */ 1431573Srgrimes (void) close(2); /* set up log file */ 1441573Srgrimes if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 1451573Srgrimes syslog(LOG_ERR, "%s: %m", LF); 1461573Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1471573Srgrimes } 1481573Srgrimes setgid(getegid()); 1491573Srgrimes pid = getpid(); /* for use with lprm */ 1501573Srgrimes setpgrp(0, pid); 1511573Srgrimes signal(SIGHUP, abortpr); 1521573Srgrimes signal(SIGINT, abortpr); 1531573Srgrimes signal(SIGQUIT, abortpr); 1541573Srgrimes signal(SIGTERM, abortpr); 1551573Srgrimes 1561573Srgrimes (void) mktemp(tempfile); 1571573Srgrimes 1581573Srgrimes /* 15987027Sfenner * uses short form file names 16087027Sfenner */ 16187027Sfenner if (chdir(SD) < 0) { 16287738Sru syslog(LOG_ERR, "%s: %m", SD); 16387027Sfenner exit(1); 16487738Sru } 16587738Sru if (stat(LO, &stb) == 0 && (stb.st_mode & 0100)) 1661573Srgrimes exit(0); /* printing disabled */ 1671573Srgrimes lfd = open(LO, O_WRONLY|O_CREAT, 0644); 1681573Srgrimes if (lfd < 0) { 1691573Srgrimes syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1701573Srgrimes exit(1); 1711573Srgrimes } 17287027Sfenner if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 17373152Sobrien if (errno == EWOULDBLOCK) /* active deamon present */ 17473152Sobrien exit(0); 17587027Sfenner syslog(LOG_ERR, "%s: %s: %m", printer, LO); 17687027Sfenner exit(1); 17787027Sfenner } 17887738Sru ftruncate(lfd, 0); 17987027Sfenner /* 18087027Sfenner * write process id for others to know 18187027Sfenner */ 18273152Sobrien sprintf(line, "%u\n", pid); 18373152Sobrien pidoff = i = strlen(line); 1841573Srgrimes if (write(lfd, line, i) != i) { 18573152Sobrien syslog(LOG_ERR, "%s: %s: %m", printer, LO); 1861573Srgrimes exit(1); 18783328Sru } 18883328Sru /* 18982975Sache * search the spool directory for work and sort by queue order. 19083328Sru */ 191140613Sache if ((nitems = getq(&queue)) < 0) { 192140613Sache syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 1931573Srgrimes exit(1); 19460075Sphantom } 19582975Sache if (nitems == 0) /* no work to do */ 19683328Sru exit(0); 19783328Sru if (stb.st_mode & 01) { /* reset queue flag */ 19883328Sru if (fchmod(lfd, stb.st_mode & 0776) < 0) 199140613Sache syslog(LOG_ERR, "%s: %s: %m", printer, LO); 200140613Sache } 2011573Srgrimes openpr(); /* open printer or remote */ 2021573Srgrimesagain: 2031573Srgrimes /* 2041573Srgrimes * we found something to do now do it -- 205104751Stjr * write the name of the current control file into the lock file 206158774Smaxim * so the spool queue program can tell what we're working on 207104751Stjr */ 2081573Srgrimes for (qp = queue; nitems--; free((char *) q)) { 2091573Srgrimes q = *qp++; 2101573Srgrimes if (stat(q->q_name, &stb) < 0) 2111573Srgrimes continue; 2121573Srgrimes restart: 21373088Sru (void) lseek(lfd, (off_t)pidoff, 0); 21473152Sobrien (void) sprintf(line, "%s\n", q->q_name); 21573152Sobrien i = strlen(line); 21687027Sfenner if (write(lfd, line, i) != i) 21787027Sfenner syslog(LOG_ERR, "%s: %s: %m", printer, LO); 21887027Sfenner if (!remote) 21987027Sfenner i = printit(q->q_name); 22073152Sobrien else 22173222Sru i = sendit(q->q_name); 22273222Sru /* 22387027Sfenner * Check to see if we are supposed to stop printing or 22473152Sobrien * 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] = "-F"; 533 av[6] = 0; 534 fo = ofd; 535 goto start; 536 } 537 pipe(p); 538 if ((prchild = dofork(DORETURN)) == 0) { /* child */ 539 dup2(fi, 0); /* file is stdin */ 540 dup2(p[1], 1); /* pipe is stdout */ 541 for (n = 3; n < NOFILE; n++) 542 (void) close(n); 543 execl(_PATH_PR, "pr", width, length, 544 "-h", *title ? title : " ", "-F", 0); 545 syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 546 exit(2); 547 } 548 (void) close(p[1]); /* close output side */ 549 (void) close(fi); 550 if (prchild < 0) { 551 prchild = 0; 552 (void) close(p[0]); 553 return(ERROR); 554 } 555 fi = p[0]; /* use pipe for input */ 556 case 'f': /* print plain text file */ 557 prog = IF; 558 av[1] = width; 559 av[2] = length; 560 av[3] = indent; 561 n = 4; 562 break; 563 case 'l': /* like 'f' but pass control characters */ 564 prog = IF; 565 av[1] = "-c"; 566 av[2] = width; 567 av[3] = length; 568 av[4] = indent; 569 n = 5; 570 break; 571 case 'r': /* print a fortran text file */ 572 prog = RF; 573 av[1] = width; 574 av[2] = length; 575 n = 3; 576 break; 577 case 't': /* print troff output */ 578 case 'n': /* print ditroff output */ 579 case 'd': /* print tex output */ 580 (void) unlink(".railmag"); 581 if ((fo = creat(".railmag", FILMOD)) < 0) { 582 syslog(LOG_ERR, "%s: cannot create .railmag", printer); 583 (void) unlink(".railmag"); 584 } else { 585 for (n = 0; n < 4; n++) { 586 if (fonts[n][0] != '/') 587 (void) write(fo, _PATH_VFONT, 588 sizeof(_PATH_VFONT) - 1); 589 (void) write(fo, fonts[n], strlen(fonts[n])); 590 (void) write(fo, "\n", 1); 591 } 592 (void) close(fo); 593 } 594 prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 595 av[1] = pxwidth; 596 av[2] = pxlength; 597 n = 3; 598 break; 599 case 'c': /* print cifplot output */ 600 prog = CF; 601 av[1] = pxwidth; 602 av[2] = pxlength; 603 n = 3; 604 break; 605 case 'g': /* print plot(1G) output */ 606 prog = GF; 607 av[1] = pxwidth; 608 av[2] = pxlength; 609 n = 3; 610 break; 611 case 'v': /* print raster output */ 612 prog = VF; 613 av[1] = pxwidth; 614 av[2] = pxlength; 615 n = 3; 616 break; 617 default: 618 (void) close(fi); 619 syslog(LOG_ERR, "%s: illegal format character '%c'", 620 printer, format); 621 return(ERROR); 622 } 623 if ((av[0] = rindex(prog, '/')) != NULL) 624 av[0]++; 625 else 626 av[0] = prog; 627 av[n++] = "-n"; 628 av[n++] = logname; 629 av[n++] = "-h"; 630 av[n++] = fromhost; 631 av[n++] = AF; 632 av[n] = 0; 633 fo = pfd; 634 if (ofilter > 0) { /* stop output filter */ 635 write(ofd, "\031\1", 2); 636 while ((pid = 637 wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter) 638 ; 639 if (status.w_stopval != WSTOPPED) { 640 (void) close(fi); 641 syslog(LOG_WARNING, "%s: output filter died (%d)", 642 printer, status.w_retcode); 643 return(REPRINT); 644 } 645 stopped++; 646 } 647start: 648 if ((child = dofork(DORETURN)) == 0) { /* child */ 649 dup2(fi, 0); 650 dup2(fo, 1); 651 n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664); 652 if (n >= 0) 653 dup2(n, 2); 654 for (n = 3; n < NOFILE; n++) 655 (void) close(n); 656 execv(prog, av); 657 syslog(LOG_ERR, "cannot execv %s", prog); 658 exit(2); 659 } 660 (void) close(fi); 661 if (child < 0) 662 status.w_retcode = 100; 663 else 664 while ((pid = wait((int *)&status)) > 0 && pid != child) 665 ; 666 child = 0; 667 prchild = 0; 668 if (stopped) { /* restart output filter */ 669 if (kill(ofilter, SIGCONT) < 0) { 670 syslog(LOG_ERR, "cannot restart output filter"); 671 exit(1); 672 } 673 } 674 tof = 0; 675 676 /* Copy filter output to "lf" logfile */ 677 if (fp = fopen(tempfile, "r")) { 678 while (fgets(buf, sizeof(buf), fp)) 679 fputs(buf, stderr); 680 fclose(fp); 681 } 682 683 if (!WIFEXITED(status)) { 684 syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)", 685 printer, format, status.w_termsig); 686 return(ERROR); 687 } 688 switch (status.w_retcode) { 689 case 0: 690 tof = 1; 691 return(OK); 692 case 1: 693 return(REPRINT); 694 default: 695 syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)", 696 printer, format, status.w_retcode); 697 case 2: 698 return(ERROR); 699 } 700} 701 702/* 703 * Send the daemon control file (cf) and any data files. 704 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and 705 * 0 if all is well. 706 */ 707static int 708sendit(file) 709 char *file; 710{ 711 register int i, err = OK; 712 char *cp, last[BUFSIZ]; 713 714 /* 715 * open control file 716 */ 717 if ((cfp = fopen(file, "r")) == NULL) 718 return(OK); 719 /* 720 * read the control file for work to do 721 * 722 * file format -- first character in the line is a command 723 * rest of the line is the argument. 724 * commands of interest are: 725 * 726 * a-z -- "file name" name of file to print 727 * U -- "unlink" name of file to remove 728 * (after we print it. (Pass 2 only)). 729 */ 730 731 /* 732 * pass 1 733 */ 734 while (getline(cfp)) { 735 again: 736 if (line[0] == 'S') { 737 cp = line+1; 738 i = 0; 739 while (*cp >= '0' && *cp <= '9') 740 i = i * 10 + (*cp++ - '0'); 741 fdev = i; 742 cp++; 743 i = 0; 744 while (*cp >= '0' && *cp <= '9') 745 i = i * 10 + (*cp++ - '0'); 746 fino = i; 747 continue; 748 } 749 if (line[0] >= 'a' && line[0] <= 'z') { 750 strcpy(last, line); 751 while (i = getline(cfp)) 752 if (strcmp(last, line)) 753 break; 754 switch (sendfile('\3', last+1)) { 755 case OK: 756 if (i) 757 goto again; 758 break; 759 case REPRINT: 760 (void) fclose(cfp); 761 return(REPRINT); 762 case ACCESS: 763 sendmail(logname, ACCESS); 764 case ERROR: 765 err = ERROR; 766 } 767 break; 768 } 769 } 770 if (err == OK && sendfile('\2', file) > 0) { 771 (void) fclose(cfp); 772 return(REPRINT); 773 } 774 /* 775 * pass 2 776 */ 777 fseek(cfp, 0L, 0); 778 while (getline(cfp)) 779 if (line[0] == 'U') 780 (void) unlink(line+1); 781 /* 782 * clean-up in case another control file exists 783 */ 784 (void) fclose(cfp); 785 (void) unlink(file); 786 return(err); 787} 788 789/* 790 * Send a data file to the remote machine and spool it. 791 * Return positive if we should try resending. 792 */ 793static int 794sendfile(type, file) 795 int type; 796 char *file; 797{ 798 register int f, i, amt; 799 struct stat stb; 800 char buf[BUFSIZ]; 801 int sizerr, resp; 802 803 if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 804 return(ERROR); 805 /* 806 * Check to see if data file is a symbolic link. If so, it should 807 * still point to the same file or someone is trying to print something 808 * he shouldn't. 809 */ 810 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 811 (stb.st_dev != fdev || stb.st_ino != fino)) 812 return(ACCESS); 813 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 814 amt = strlen(buf); 815 for (i = 0; ; i++) { 816 if (write(pfd, buf, amt) != amt || 817 (resp = response()) < 0 || resp == '\1') { 818 (void) close(f); 819 return(REPRINT); 820 } else if (resp == '\0') 821 break; 822 if (i == 0) 823 pstatus("no space on remote; waiting for queue to drain"); 824 if (i == 10) 825 syslog(LOG_ALERT, "%s: can't send to %s; queue full", 826 printer, RM); 827 sleep(5 * 60); 828 } 829 if (i) 830 pstatus("sending to %s", RM); 831 sizerr = 0; 832 for (i = 0; i < stb.st_size; i += BUFSIZ) { 833 amt = BUFSIZ; 834 if (i + amt > stb.st_size) 835 amt = stb.st_size - i; 836 if (sizerr == 0 && read(f, buf, amt) != amt) 837 sizerr = 1; 838 if (write(pfd, buf, amt) != amt) { 839 (void) close(f); 840 return(REPRINT); 841 } 842 } 843 844 845 846 847 (void) close(f); 848 if (sizerr) { 849 syslog(LOG_INFO, "%s: %s: changed size", printer, file); 850 /* tell recvjob to ignore this file */ 851 (void) write(pfd, "\1", 1); 852 return(ERROR); 853 } 854 if (write(pfd, "", 1) != 1 || response()) 855 return(REPRINT); 856 return(OK); 857} 858 859/* 860 * Check to make sure there have been no errors and that both programs 861 * are in sync with eachother. 862 * Return non-zero if the connection was lost. 863 */ 864static char 865response() 866{ 867 char resp; 868 869 if (read(pfd, &resp, 1) != 1) { 870 syslog(LOG_INFO, "%s: lost connection", printer); 871 return(-1); 872 } 873 return(resp); 874} 875 876/* 877 * Banner printing stuff 878 */ 879static void 880banner(name1, name2) 881 char *name1, *name2; 882{ 883 time_t tvec; 884 extern char *ctime(); 885 886 time(&tvec); 887 if (!SF && !tof) 888 (void) write(ofd, FF, strlen(FF)); 889 if (SB) { /* short banner only */ 890 if (class[0]) { 891 (void) write(ofd, class, strlen(class)); 892 (void) write(ofd, ":", 1); 893 } 894 (void) write(ofd, name1, strlen(name1)); 895 (void) write(ofd, " Job: ", 7); 896 (void) write(ofd, name2, strlen(name2)); 897 (void) write(ofd, " Date: ", 8); 898 (void) write(ofd, ctime(&tvec), 24); 899 (void) write(ofd, "\n", 1); 900 } else { /* normal banner */ 901 (void) write(ofd, "\n\n\n", 3); 902 scan_out(ofd, name1, '\0'); 903 (void) write(ofd, "\n\n", 2); 904 scan_out(ofd, name2, '\0'); 905 if (class[0]) { 906 (void) write(ofd,"\n\n\n",3); 907 scan_out(ofd, class, '\0'); 908 } 909 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 910 (void) write(ofd, name2, strlen(name2)); 911 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12); 912 (void) write(ofd, ctime(&tvec), 24); 913 (void) write(ofd, "\n", 1); 914 } 915 if (!SF) 916 (void) write(ofd, FF, strlen(FF)); 917 tof = 1; 918} 919 920static char * 921scnline(key, p, c) 922 register int key; 923 register char *p; 924 int c; 925{ 926 register scnwidth; 927 928 for (scnwidth = WIDTH; --scnwidth;) { 929 key <<= 1; 930 *p++ = key & 0200 ? c : BACKGND; 931 } 932 return (p); 933} 934 935#define TRC(q) (((q)-' ')&0177) 936 937static void 938scan_out(scfd, scsp, dlm) 939 int scfd, dlm; 940 char *scsp; 941{ 942 register char *strp; 943 register nchrs, j; 944 char outbuf[LINELEN+1], *sp, c, cc; 945 int d, scnhgt; 946 extern char scnkey[][HEIGHT]; /* in lpdchar.c */ 947 948 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 949 strp = &outbuf[0]; 950 sp = scsp; 951 for (nchrs = 0; ; ) { 952 d = dropit(c = TRC(cc = *sp++)); 953 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 954 for (j = WIDTH; --j;) 955 *strp++ = BACKGND; 956 else 957 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc); 958 if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1) 959 break; 960 *strp++ = BACKGND; 961 *strp++ = BACKGND; 962 } 963 while (*--strp == BACKGND && strp >= outbuf) 964 ; 965 strp++; 966 *strp++ = '\n'; 967 (void) write(scfd, outbuf, strp-outbuf); 968 } 969} 970 971static int 972dropit(c) 973 int c; 974{ 975 switch(c) { 976 977 case TRC('_'): 978 case TRC(';'): 979 case TRC(','): 980 case TRC('g'): 981 case TRC('j'): 982 case TRC('p'): 983 case TRC('q'): 984 case TRC('y'): 985 return (DROP); 986 987 default: 988 return (0); 989 } 990} 991 992/* 993 * sendmail --- 994 * tell people about job completion 995 */ 996static void 997sendmail(user, bombed) 998 char *user; 999 int bombed; 1000{ 1001 register int i; 1002 int p[2], s; 1003 register char *cp; 1004 char buf[100]; 1005 struct stat stb; 1006 FILE *fp; 1007 1008 pipe(p); 1009 if ((s = dofork(DORETURN)) == 0) { /* child */ 1010 dup2(p[0], 0); 1011 for (i = 3; i < NOFILE; i++) 1012 (void) close(i); 1013 if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL) 1014 cp++; 1015 else 1016 cp = _PATH_SENDMAIL; 1017 sprintf(buf, "%s@%s", user, fromhost); 1018 execl(_PATH_SENDMAIL, cp, buf, 0); 1019 exit(0); 1020 } else if (s > 0) { /* parent */ 1021 dup2(p[1], 1); 1022 printf("To: %s@%s\n", user, fromhost); 1023 printf("Subject: printer job\n\n"); 1024 printf("Your printer job "); 1025 if (*jobname) 1026 printf("(%s) ", jobname); 1027 switch (bombed) { 1028 case OK: 1029 printf("\ncompleted successfully\n"); 1030 break; 1031 default: 1032 case FATALERR: 1033 printf("\ncould not be printed\n"); 1034 break; 1035 case NOACCT: 1036 printf("\ncould not be printed without an account on %s\n", host); 1037 break; 1038 case FILTERERR: 1039 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1040 (fp = fopen(tempfile, "r")) == NULL) { 1041 printf("\nwas printed but had some errors\n"); 1042 break; 1043 } 1044 printf("\nwas printed but had the following errors:\n"); 1045 while ((i = getc(fp)) != EOF) 1046 putchar(i); 1047 (void) fclose(fp); 1048 break; 1049 case ACCESS: 1050 printf("\nwas not printed because it was not linked to the original file\n"); 1051 } 1052 fflush(stdout); 1053 (void) close(1); 1054 } 1055 (void) close(p[0]); 1056 (void) close(p[1]); 1057 wait(&s); 1058} 1059 1060/* 1061 * dofork - fork with retries on failure 1062 */ 1063static int 1064dofork(action) 1065 int action; 1066{ 1067 register int i, pid; 1068 1069 for (i = 0; i < 20; i++) { 1070 if ((pid = fork()) < 0) { 1071 sleep((unsigned)(i*i)); 1072 continue; 1073 } 1074 /* 1075 * Child should run as daemon instead of root 1076 */ 1077 if (pid == 0) 1078 setuid(DU); 1079 return(pid); 1080 } 1081 syslog(LOG_ERR, "can't fork"); 1082 1083 switch (action) { 1084 case DORETURN: 1085 return (-1); 1086 default: 1087 syslog(LOG_ERR, "bad action (%d) to dofork", action); 1088 /*FALL THRU*/ 1089 case DOABORT: 1090 exit(1); 1091 } 1092 /*NOTREACHED*/ 1093} 1094 1095/* 1096 * Kill child processes to abort current job. 1097 */ 1098static void 1099abortpr(signo) 1100 int signo; 1101{ 1102 (void) unlink(tempfile); 1103 kill(0, SIGINT); 1104 if (ofilter > 0) 1105 kill(ofilter, SIGCONT); 1106 while (wait(NULL) > 0) 1107 ; 1108 exit(0); 1109} 1110 1111static void 1112init() 1113{ 1114 int status; 1115 char *s; 1116 1117 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1118 syslog(LOG_ERR, "can't open printer description file"); 1119 exit(1); 1120 } else if (status == -1) { 1121 syslog(LOG_ERR, "unknown printer: %s", printer); 1122 exit(1); 1123 } else if (status == -3) 1124 fatal("potential reference loop detected in printcap file"); 1125 1126 if (cgetstr(bp, "lp", &LP) == -1) 1127 LP = _PATH_DEFDEVLP; 1128 if (cgetstr(bp, "rp", &RP) == -1) 1129 RP = DEFLP; 1130 if (cgetstr(bp, "lo", &LO) == -1) 1131 LO = DEFLOCK; 1132 if (cgetstr(bp, "st", &ST) == -1) 1133 ST = DEFSTAT; 1134 if (cgetstr(bp, "lf", &LF) == -1) 1135 LF = _PATH_CONSOLE; 1136 if (cgetstr(bp, "sd", &SD) == -1) 1137 SD = _PATH_DEFSPOOL; 1138 if (cgetnum(bp, "du", &DU) < 0) 1139 DU = DEFUID; 1140 if (cgetstr(bp,"ff", &FF) == -1) 1141 FF = DEFFF; 1142 if (cgetnum(bp, "pw", &PW) < 0) 1143 PW = DEFWIDTH; 1144 sprintf(&width[2], "%d", PW); 1145 if (cgetnum(bp, "pl", &PL) < 0) 1146 PL = DEFLENGTH; 1147 sprintf(&length[2], "%d", PL); 1148 if (cgetnum(bp,"px", &PX) < 0) 1149 PX = 0; 1150 sprintf(&pxwidth[2], "%d", PX); 1151 if (cgetnum(bp, "py", &PY) < 0) 1152 PY = 0; 1153 sprintf(&pxlength[2], "%d", PY); 1154 cgetstr(bp, "rm", &RM); 1155 if (s = checkremote()) 1156 syslog(LOG_WARNING, s); 1157 1158 cgetstr(bp, "af", &AF); 1159 cgetstr(bp, "of", &OF); 1160 cgetstr(bp, "if", &IF); 1161 cgetstr(bp, "rf", &RF); 1162 cgetstr(bp, "tf", &TF); 1163 cgetstr(bp, "nf", &NF); 1164 cgetstr(bp, "df", &DF); 1165 cgetstr(bp, "gf", &GF); 1166 cgetstr(bp, "vf", &VF); 1167 cgetstr(bp, "cf", &CF); 1168 cgetstr(bp, "tr", &TR); 1169 1170 RS = (cgetcap(bp, "rs", ':') != NULL); 1171 SF = (cgetcap(bp, "sf", ':') != NULL); 1172 SH = (cgetcap(bp, "sh", ':') != NULL); 1173 SB = (cgetcap(bp, "sb", ':') != NULL); 1174 HL = (cgetcap(bp, "hl", ':') != NULL); 1175 RW = (cgetcap(bp, "rw", ':') != NULL); 1176 1177 cgetnum(bp, "br", &BR); 1178 if (cgetnum(bp, "fc", &FC) < 0) 1179 FC = 0; 1180 if (cgetnum(bp, "fs", &FS) < 0) 1181 FS = 0; 1182 if (cgetnum(bp, "xc", &XC) < 0) 1183 XC = 0; 1184 if (cgetnum(bp, "xs", &XS) < 0) 1185 XS = 0; 1186 1187 tof = (cgetcap(bp, "fo", ':') == NULL); 1188} 1189 1190/* 1191 * Acquire line printer or remote connection. 1192 */ 1193static void 1194openpr() 1195{ 1196 register int i, n; 1197 int resp; 1198 1199 if (!sendtorem && *LP) { 1200 for (i = 1; ; i = i < 32 ? i << 1 : i) { 1201 pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1202 if (pfd >= 0) 1203 break; 1204 if (errno == ENOENT) { 1205 syslog(LOG_ERR, "%s: %m", LP); 1206 exit(1); 1207 } 1208 if (i == 1) 1209 pstatus("waiting for %s to become ready (offline ?)", printer); 1210 sleep(i); 1211 } 1212 if (isatty(pfd)) 1213 setty(); 1214 pstatus("%s is ready and printing", printer); 1215 } else if (RM != NULL) { 1216 for (i = 1; ; i = i < 256 ? i << 1 : i) { 1217 resp = -1; 1218 pfd = getport(RM); 1219 if (pfd >= 0) { 1220 (void) sprintf(line, "\2%s\n", RP); 1221 n = strlen(line); 1222 if (write(pfd, line, n) == n && 1223 (resp = response()) == '\0') 1224 break; 1225 (void) close(pfd); 1226 } 1227 if (i == 1) { 1228 if (resp < 0) 1229 pstatus("waiting for %s to come up", RM); 1230 else { 1231 pstatus("waiting for queue to be enabled on %s", RM); 1232 i = 256; 1233 } 1234 } 1235 sleep(i); 1236 } 1237 pstatus("sending to %s", RM); 1238 remote = 1; 1239 } else { 1240 syslog(LOG_ERR, "%s: no line printer device or host name", 1241 printer); 1242 exit(1); 1243 } 1244 /* 1245 * Start up an output filter, if needed. 1246 */ 1247 if (!remote && OF) { 1248 int p[2]; 1249 char *cp; 1250 1251 pipe(p); 1252 if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1253 dup2(p[0], 0); /* pipe is std in */ 1254 dup2(pfd, 1); /* printer is std out */ 1255 for (i = 3; i < NOFILE; i++) 1256 (void) close(i); 1257 if ((cp = rindex(OF, '/')) == NULL) 1258 cp = OF; 1259 else 1260 cp++; 1261 execl(OF, cp, width, length, 0); 1262 syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1263 exit(1); 1264 } 1265 (void) close(p[0]); /* close input side */ 1266 ofd = p[1]; /* use pipe for output */ 1267 } else { 1268 ofd = pfd; 1269 ofilter = 0; 1270 } 1271} 1272 1273struct bauds { 1274 int baud; 1275 int speed; 1276} bauds[] = { 1277 50, B50, 1278 75, B75, 1279 110, B110, 1280 134, B134, 1281 150, B150, 1282 200, B200, 1283 300, B300, 1284 600, B600, 1285 1200, B1200, 1286 1800, B1800, 1287 2400, B2400, 1288 4800, B4800, 1289 9600, B9600, 1290 19200, EXTA, 1291 38400, EXTB, 1292 0, 0 1293}; 1294 1295/* 1296 * setup tty lines. 1297 */ 1298static void 1299setty() 1300{ 1301 struct sgttyb ttybuf; 1302 register struct bauds *bp; 1303 1304 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) { 1305 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1306 exit(1); 1307 } 1308 if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) { 1309 syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer); 1310 exit(1); 1311 } 1312 if (BR > 0) { 1313 for (bp = bauds; bp->baud; bp++) 1314 if (BR == bp->baud) 1315 break; 1316 if (!bp->baud) { 1317 syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1318 exit(1); 1319 } 1320 ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed; 1321 } 1322 ttybuf.sg_flags &= ~FC; 1323 ttybuf.sg_flags |= FS; 1324 if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) { 1325 syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer); 1326 exit(1); 1327 } 1328 if (XC) { 1329 if (ioctl(pfd, TIOCLBIC, &XC) < 0) { 1330 syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer); 1331 exit(1); 1332 } 1333 } 1334 if (XS) { 1335 if (ioctl(pfd, TIOCLBIS, &XS) < 0) { 1336 syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer); 1337 exit(1); 1338 } 1339 } 1340} 1341 1342#if __STDC__ 1343#include <stdarg.h> 1344#else 1345#include <varargs.h> 1346#endif 1347 1348void 1349#if __STDC__ 1350pstatus(const char *msg, ...) 1351#else 1352pstatus(msg, va_alist) 1353 char *msg; 1354 va_dcl 1355#endif 1356{ 1357 register int fd; 1358 char buf[BUFSIZ]; 1359 va_list ap; 1360#if __STDC__ 1361 va_start(ap, msg); 1362#else 1363 va_start(ap); 1364#endif 1365 1366 umask(0); 1367 fd = open(ST, O_WRONLY|O_CREAT, 0664); 1368 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1369 syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1370 exit(1); 1371 } 1372 ftruncate(fd, 0); 1373 (void)vsnprintf(buf, sizeof(buf), msg, ap); 1374 va_end(ap); 1375 strcat(buf, "\n"); 1376 (void) write(fd, buf, strlen(buf)); 1377 (void) close(fd); 1378} 1379