1*33262Ssklower #ifndef lint 2*33262Ssklower static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated"; 3*33262Ssklower static char *RCSID="$Header: pscomm.bsd,v 2.1 85/11/24 11:50:16 shore Rel $"; 4*33262Ssklower #endif 5*33262Ssklower /* pscomm.c 6*33262Ssklower * 7*33262Ssklower * Copyright (C) 1985 Adobe Systems Incorporated 8*33262Ssklower * 9*33262Ssklower * 4.2BSD lpr/lpd communications filter for PostScript printers 10*33262Ssklower * (formerly "psif" in TranScript release 1.0) 11*33262Ssklower * 12*33262Ssklower * pscomm is the general communications filter for 13*33262Ssklower * sending files to a PostScript printer (e.g., an Apple LaserWriter, 14*33262Ssklower * QMS PostScript printer, or Linotype PostScript typesetter) 15*33262Ssklower * via RS232 lines. It does page accounting, error handling/reporting, 16*33262Ssklower * job logging, banner page printing, etc. 17*33262Ssklower * It observes (parts of) the PostScript file structuring conventions. 18*33262Ssklower * In particular, it distinguishes between PostScript files (beginning 19*33262Ssklower * with the "%!" magic number) -- which are shipped to the printer -- 20*33262Ssklower * and text files (no magic number) which are formatted and listed 21*33262Ssklower * on the printer. Files which begin with "%!PS-Adobe-" may be 22*33262Ssklower * page-reversed if the target printer has that option specified. 23*33262Ssklower * 24*33262Ssklower * depending on the values of BANNERFIRST and BANNERLAST, 25*33262Ssklower * pscomm looks for a file named ".banner", (created by the "of" filter) 26*33262Ssklower * in the current working directory and ships it to the printer also. 27*33262Ssklower * 28*33262Ssklower * pscomm gets called with: 29*33262Ssklower * stdin == the file to print (may be a pipe!) 30*33262Ssklower * stdout == the printer 31*33262Ssklower * stderr == the printer log file 32*33262Ssklower * cwd == the spool directory 33*33262Ssklower * argv == set up by interface shell script: 34*33262Ssklower * filtername -P printer 35*33262Ssklower * -p filtername 36*33262Ssklower * [-r] (don't ever reverse) 37*33262Ssklower * -n login 38*33262Ssklower * -h host 39*33262Ssklower * [accntfile] 40*33262Ssklower * 41*33262Ssklower * environ == various environment variable effect behavior 42*33262Ssklower * VERBOSELOG - do verbose log file output 43*33262Ssklower * BANNERFIRST - print .banner before job 44*33262Ssklower * BANNERLAST - print .banner after job 45*33262Ssklower * REVERSE - page reversal filter program 46*33262Ssklower * (no reversal if null or missing) 47*33262Ssklower * PSLIBDIR - transcript library directory 48*33262Ssklower * PSTEXT - simple text formatting filter 49*33262Ssklower * JOBOUTPUT - file for actual printer stream 50*33262Ssklower * output (if defined) 51*33262Ssklower * 52*33262Ssklower * pscomm depends on certain additional features of the 4.2BSD spooling 53*33262Ssklower * architecture. In particular it assumes that the printer status file 54*33262Ssklower * has the default name (./status) and it uses this file to communicate 55*33262Ssklower * printer error status information to the user -- the contents of the 56*33262Ssklower * status file gets incorporated in "lpq" and "lpc status" messages. 57*33262Ssklower * 58*33262Ssklower * Edit History: 59*33262Ssklower * Andrew Shore: Sat Nov 16 11:59:58 1985 60*33262Ssklower * End Edit History. 61*33262Ssklower * 62*33262Ssklower * RCSLOG: 63*33262Ssklower * $Log: pscomm.bsd,v $ 64*33262Ssklower * Revision 2.1 85/11/24 11:50:16 shore 65*33262Ssklower * Product Release 2.0 66*33262Ssklower * 67*33262Ssklower * Revision 1.1 85/11/20 00:35:21 shore 68*33262Ssklower * Initial revision 69*33262Ssklower * 70*33262Ssklower * Revision 1.2 85/05/14 11:25:29 shore 71*33262Ssklower * better support for BANNERLAST, still buggy though 72*33262Ssklower * 73*33262Ssklower * 74*33262Ssklower */ 75*33262Ssklower 76*33262Ssklower #include <ctype.h> 77*33262Ssklower #include <setjmp.h> 78*33262Ssklower #include <sgtty.h> 79*33262Ssklower #include <signal.h> 80*33262Ssklower #include <stdio.h> 81*33262Ssklower #include <strings.h> 82*33262Ssklower 83*33262Ssklower #include <sys/file.h> 84*33262Ssklower #include <sys/ioctl.h> 85*33262Ssklower #include <sys/time.h> 86*33262Ssklower #include <sys/resource.h> 87*33262Ssklower #include <sys/wait.h> 88*33262Ssklower #include <sys/types.h> 89*33262Ssklower #include <sys/stat.h> 90*33262Ssklower 91*33262Ssklower #include "transcript.h" 92*33262Ssklower #include "psspool.h" 93*33262Ssklower 94*33262Ssklower #ifdef BDEBUG 95*33262Ssklower #define debugp(x) {fprintf x ; (void) fflush(stderr);} 96*33262Ssklower #else 97*33262Ssklower #define debugp(x) 98*33262Ssklower #endif BDEBUG 99*33262Ssklower 100*33262Ssklower /* 101*33262Ssklower * the following string is sent to the printer when we want it to 102*33262Ssklower * report its current pagecount (for accounting) 103*33262Ssklower */ 104*33262Ssklower 105*33262Ssklower private char *getpages = "\n(%%%%[ pagecount: )print \ 106*33262Ssklower statusdict/pagecount get exec( )cvs print( ]%%%%)= flush\n%s"; 107*33262Ssklower 108*33262Ssklower private jmp_buf waitonreverse, startstatus, dwait, sendint; 109*33262Ssklower 110*33262Ssklower private char *prog; /* invoking program name */ 111*33262Ssklower private char *name; /* user login name */ 112*33262Ssklower private char *host; /* host name */ 113*33262Ssklower private char *pname; /* printer name */ 114*33262Ssklower private char *accountingfile; /* file for printer accounting */ 115*33262Ssklower private int doactng; /* true if we can do accounting */ 116*33262Ssklower private int progress, oldprogress; /* finite progress counts */ 117*33262Ssklower private int getstatus = FALSE; 118*33262Ssklower private int revdone = FALSE; /* reverse done, send new */ 119*33262Ssklower private int goahead = FALSE; /* got initial status back */ 120*33262Ssklower private int gotemt = FALSE; /* got ^D ack from listener */ 121*33262Ssklower private int sendend = TRUE; /* send an ^D */ 122*33262Ssklower 123*33262Ssklower private char *bannerfirst; 124*33262Ssklower private char *bannerlast; 125*33262Ssklower private char *verboselog; 126*33262Ssklower private char *reverse; 127*33262Ssklower private int BannerFirst; 128*33262Ssklower private int BannerLast; 129*33262Ssklower private int VerboseLog; 130*33262Ssklower 131*33262Ssklower private int fpid = 0; /* formatter pid */ 132*33262Ssklower private int cpid = 0; /* listener pid */ 133*33262Ssklower 134*33262Ssklower private int intrup = FALSE; /* interrupt flag */ 135*33262Ssklower 136*33262Ssklower private char abortbuf[] = "\003"; /* ^C abort */ 137*33262Ssklower private char statusbuf[] = "\024"; /* ^T status */ 138*33262Ssklower private char eofbuf[] = "\004"; /* ^D end of file */ 139*33262Ssklower 140*33262Ssklower private char EOFerr[] = "%s: unexpected EOF from printer (%s)!\n"; 141*33262Ssklower 142*33262Ssklower /* global file descriptors (avoid stdio buffering!) */ 143*33262Ssklower private int fdsend; /* to printer (from stdout) */ 144*33262Ssklower private int fdlisten; /* from printer (same tty line) */ 145*33262Ssklower private int fdinput; /* file to print (from stdin) */ 146*33262Ssklower 147*33262Ssklower private FILE *jobout; /* special printer output log */ 148*33262Ssklower 149*33262Ssklower private int flg = FREAD|FWRITE; /* ioctl FLUSH arg */ 150*33262Ssklower 151*33262Ssklower 152*33262Ssklower extern char *getenv(); 153*33262Ssklower 154*33262Ssklower private VOID intinit(); 155*33262Ssklower private VOID intsend(); 156*33262Ssklower private VOID intwait(); 157*33262Ssklower private VOID salarm(); 158*33262Ssklower private VOID walarm(); 159*33262Ssklower private VOID falarm(); 160*33262Ssklower private VOID reverseready(); 161*33262Ssklower private VOID readynow(); 162*33262Ssklower private VOID emtdead(); 163*33262Ssklower private VOID emtdone(); 164*33262Ssklower private char *FindPattern(); 165*33262Ssklower 166*33262Ssklower #define SENDALARM 90 167*33262Ssklower #define WAITALARM 30 168*33262Ssklower 169*33262Ssklower main(argc,argv) 170*33262Ssklower int argc; 171*33262Ssklower char *argv[]; 172*33262Ssklower { 173*33262Ssklower register char *cp; 174*33262Ssklower register int cnt, wc; 175*33262Ssklower register char *mbp; 176*33262Ssklower 177*33262Ssklower char **av; 178*33262Ssklower long clock; /* for log timestamp */ 179*33262Ssklower char magic[11]; /* first few bytes of stdin ?magic number and type */ 180*33262Ssklower int noReverse = 0; /* flag if we should never page reverse */ 181*33262Ssklower int canReverse = 0;/* flag if we can page-reverse the ps file */ 182*33262Ssklower int reversing = 0; 183*33262Ssklower FILE *streamin; 184*33262Ssklower 185*33262Ssklower char mybuf[BUFSIZ]; 186*33262Ssklower int wpid; 187*33262Ssklower union wait status; 188*33262Ssklower int fdpipe[2]; 189*33262Ssklower int format = 0; 190*33262Ssklower int i; 191*33262Ssklower 192*33262Ssklower VOIDC signal(SIGINT, intinit); 193*33262Ssklower VOIDC signal(SIGHUP, intinit); 194*33262Ssklower VOIDC signal(SIGQUIT, intinit); 195*33262Ssklower VOIDC signal(SIGTERM, intinit); 196*33262Ssklower 197*33262Ssklower /* parse command-line arguments */ 198*33262Ssklower /* the argv (see header comments) comes from the spooler daemon */ 199*33262Ssklower /* itself, so it should be canonical, but at least one 4.2-based */ 200*33262Ssklower /* system uses -nlogin -hhost (insead of -n login -h host) so I */ 201*33262Ssklower /* check for both */ 202*33262Ssklower 203*33262Ssklower av = argv; 204*33262Ssklower prog = *av; 205*33262Ssklower 206*33262Ssklower while (--argc) { 207*33262Ssklower if (*(cp = *++av) == '-') { 208*33262Ssklower switch (*(cp + 1)) { 209*33262Ssklower case 'P': /* printer name */ 210*33262Ssklower argc--; 211*33262Ssklower pname = *(++av); 212*33262Ssklower break; 213*33262Ssklower 214*33262Ssklower case 'n': /* user name */ 215*33262Ssklower argc--; 216*33262Ssklower name = *(++av); 217*33262Ssklower break; 218*33262Ssklower 219*33262Ssklower case 'h': /* host */ 220*33262Ssklower argc--; 221*33262Ssklower host = *(++av); 222*33262Ssklower break; 223*33262Ssklower 224*33262Ssklower case 'p': /* prog */ 225*33262Ssklower argc--; 226*33262Ssklower prog = *(++av); 227*33262Ssklower break; 228*33262Ssklower 229*33262Ssklower case 'r': /* never reverse */ 230*33262Ssklower argc--; 231*33262Ssklower noReverse = 1; 232*33262Ssklower break; 233*33262Ssklower 234*33262Ssklower default: /* unknown */ 235*33262Ssklower fprintf(stderr,"%s: unknown option: %s\n",prog,cp); 236*33262Ssklower break; 237*33262Ssklower } 238*33262Ssklower } 239*33262Ssklower else 240*33262Ssklower accountingfile = cp; 241*33262Ssklower } 242*33262Ssklower 243*33262Ssklower debugp((stderr,"args: %s %s %s %s\n",prog,host,name,accountingfile)); 244*33262Ssklower 245*33262Ssklower /* do printer-specific options processing */ 246*33262Ssklower 247*33262Ssklower VerboseLog = 1; 248*33262Ssklower BannerFirst = BannerLast = 0; 249*33262Ssklower reverse = NULL; 250*33262Ssklower if (bannerfirst=envget("BANNERFIRST")) { 251*33262Ssklower BannerFirst=atoi(bannerfirst); 252*33262Ssklower } 253*33262Ssklower if (bannerlast=envget("BANNERLAST")) { 254*33262Ssklower BannerLast=atoi(bannerlast); 255*33262Ssklower } 256*33262Ssklower if (verboselog=envget("VERBOSELOG")) { 257*33262Ssklower VerboseLog=atoi(verboselog); 258*33262Ssklower } 259*33262Ssklower if (!noReverse) { 260*33262Ssklower reverse=envget("REVERSE"); /* name of the filter itself */ 261*33262Ssklower } 262*33262Ssklower 263*33262Ssklower if (VerboseLog) { 264*33262Ssklower fprintf(stderr, "%s: %s:%s %s start - %s", prog, host, name, pname, 265*33262Ssklower (VOIDC time(&clock), ctime(&clock))); 266*33262Ssklower VOIDC fflush(stderr); 267*33262Ssklower } 268*33262Ssklower debugp((stderr,"%s: pid %d ppid %d\n",prog,getpid(),getppid())); 269*33262Ssklower debugp((stderr,"%s: options BF %d BL %d VL %d R %s\n",prog,BannerFirst, 270*33262Ssklower BannerLast, VerboseLog, ((reverse == NULL) ? "norev": reverse))); 271*33262Ssklower 272*33262Ssklower /* IMPORTANT: in the case of cascaded filters, */ 273*33262Ssklower /* stdin may be a pipe! (and hence we cannot seek!) */ 274*33262Ssklower 275*33262Ssklower if ((cnt = read(fileno(stdin),magic,11)) != 11) goto badfile; 276*33262Ssklower debugp((stderr,"%s: magic number is %11.11s\n",prog,magic)); 277*33262Ssklower streamin = stdin; 278*33262Ssklower 279*33262Ssklower if (strncmp(magic,"%!PS-Adobe-",11) == 0) { 280*33262Ssklower canReverse = TRUE; 281*33262Ssklower goto go_ahead; 282*33262Ssklower } 283*33262Ssklower else if (strncmp(magic,"%!",2) == 0) { 284*33262Ssklower canReverse = FALSE; 285*33262Ssklower goto go_ahead; 286*33262Ssklower } 287*33262Ssklower 288*33262Ssklower /* here is where you might test for other file type 289*33262Ssklower * e.g., PRESS, imPRESS, DVI, Mac-generated, etc. 290*33262Ssklower */ 291*33262Ssklower 292*33262Ssklower /* final sanity check on the text file, to guard 293*33262Ssklower * against arbitrary binary data 294*33262Ssklower */ 295*33262Ssklower 296*33262Ssklower for (i = 0; i < 11; i++) { 297*33262Ssklower if (!isascii(magic[i]) || (!isprint(magic[i]) && !isspace(magic[i]))){ 298*33262Ssklower fprintf(stderr,"%s: spooled binary file rejected\n",prog); 299*33262Ssklower VOIDC fflush(stderr); 300*33262Ssklower sprintf(mybuf,"%s/bogusmsg.ps",envget("PSLIBDIR")); 301*33262Ssklower if ((streamin = freopen(mybuf,"r",stdin)) == NULL) { 302*33262Ssklower exit(THROW_AWAY); 303*33262Ssklower } 304*33262Ssklower format = 1; 305*33262Ssklower goto lastchance; 306*33262Ssklower } 307*33262Ssklower } 308*33262Ssklower 309*33262Ssklower goto format_text; 310*33262Ssklower 311*33262Ssklower badfile: 312*33262Ssklower fprintf(stderr,"%s: bad magic number, EOF\n", prog); 313*33262Ssklower VOIDC fflush(stderr); 314*33262Ssklower exit(THROW_AWAY); 315*33262Ssklower 316*33262Ssklower format_text: 317*33262Ssklower /* exec dumb formatter to make a listing */ 318*33262Ssklower debugp((stderr,"formatting\n")); 319*33262Ssklower format = 1; 320*33262Ssklower VOIDC lseek(0,0L,0); 321*33262Ssklower rewind(stdin); 322*33262Ssklower if (pipe (fdpipe)) pexit2(prog, "format pipe",THROW_AWAY); 323*33262Ssklower if ((fpid = fork()) < 0) pexit2(prog, "format fork",THROW_AWAY); 324*33262Ssklower if (fpid == 0) { /* child */ 325*33262Ssklower /* set up child stdout to feed parent stdin */ 326*33262Ssklower if (close(1) || (dup(fdpipe[1]) != 1) 327*33262Ssklower || close(fdpipe[1]) || close(fdpipe[0])) { 328*33262Ssklower pexit2(prog, "format child",THROW_AWAY); 329*33262Ssklower } 330*33262Ssklower execl(envget("PSTEXT"), "pstext", pname, 0); 331*33262Ssklower pexit2(prog,"format exec",THROW_AWAY); 332*33262Ssklower } 333*33262Ssklower /* parent continues */ 334*33262Ssklower /* set up stdin to be pipe */ 335*33262Ssklower if (close(0) || (dup(fdpipe[0]) != 0) 336*33262Ssklower || close(fdpipe[0]) || close(fdpipe[1])) { 337*33262Ssklower pexit2(prog, "format parent",THROW_AWAY); 338*33262Ssklower } 339*33262Ssklower 340*33262Ssklower /* fall through to spooler with new stdin */ 341*33262Ssklower /* can't seek here but we should be at the right place */ 342*33262Ssklower streamin = fdopen(0,"r"); 343*33262Ssklower canReverse = TRUE; /* we know we can reverse pstext output */ 344*33262Ssklower 345*33262Ssklower go_ahead: 346*33262Ssklower 347*33262Ssklower /* do page reversal if specified */ 348*33262Ssklower if (reversing = ((reverse != NULL) && canReverse)) { 349*33262Ssklower debugp((stderr,"reversing\n")); 350*33262Ssklower VOIDC setjmp(waitonreverse); 351*33262Ssklower if (!revdone) { 352*33262Ssklower VOIDC signal(SIGEMT, reverseready); 353*33262Ssklower if (pipe (fdpipe)) pexit2(prog, "reverse pipe", THROW_AWAY); 354*33262Ssklower if ((fpid = fork()) < 0) pexit2(prog, "reverse fork", THROW_AWAY); 355*33262Ssklower if (fpid == 0) { /* child */ 356*33262Ssklower /* set up child stdout to feed parent stdin */ 357*33262Ssklower if (close(1) || (dup(fdpipe[1]) != 1) 358*33262Ssklower || close(fdpipe[1]) || close(fdpipe[0])) { 359*33262Ssklower pexit2(prog, "reverse child", THROW_AWAY); 360*33262Ssklower } 361*33262Ssklower execl(reverse, "psrv", pname, 0); 362*33262Ssklower pexit2(prog,"reverse exec",THROW_AWAY); 363*33262Ssklower } 364*33262Ssklower /* parent continues */ 365*33262Ssklower if (close(0) || (dup(fdpipe[0]) != 0) 366*33262Ssklower || close(fdpipe[0]) || close(fdpipe[1])) { 367*33262Ssklower pexit2(prog, "reverse parent", THROW_AWAY); 368*33262Ssklower } 369*33262Ssklower /* fall through to spooler with new stdin */ 370*33262Ssklower /* VOIDC lseek(0,0L,0); */ 371*33262Ssklower streamin = fdopen(0,"r"); 372*33262Ssklower 373*33262Ssklower while (TRUE) { 374*33262Ssklower if (revdone) break; 375*33262Ssklower pause(); 376*33262Ssklower } 377*33262Ssklower } 378*33262Ssklower VOIDC signal(SIGEMT, SIG_IGN); 379*33262Ssklower debugp((stderr,"%s: reverse feeding\n",prog)); 380*33262Ssklower } 381*33262Ssklower 382*33262Ssklower lastchance:; 383*33262Ssklower 384*33262Ssklower /* establish an input stream from the printer -- 385*33262Ssklower * the printcap entry specifies "rw" and we get 386*33262Ssklower * invoked with stdout == the device, so we 387*33262Ssklower * dup stdout, and reopen it for reading; 388*33262Ssklower * this seems to work fine... 389*33262Ssklower */ 390*33262Ssklower 391*33262Ssklower fdinput = fileno(streamin); /* the file to print */ 392*33262Ssklower fdsend = fileno(stdout); /* the printer (write) */ 393*33262Ssklower 394*33262Ssklower if ((fdlisten = dup(fdsend)) < 0) /* the printer (read) */ 395*33262Ssklower pexit(prog, THROW_AWAY); 396*33262Ssklower 397*33262Ssklower doactng = name && accountingfile && (access(accountingfile, W_OK) == 0); 398*33262Ssklower 399*33262Ssklower /* get control of the "status" message file. 400*33262Ssklower * we copy the current one to ".status" so we can restore it 401*33262Ssklower * on exit (to be clean). 402*33262Ssklower * Our ability to use this is publicized nowhere in the 403*33262Ssklower * 4.2 lpr documentation, so things might go bad for us. 404*33262Ssklower * We will use it to report that printer errors condition 405*33262Ssklower * has been detected, and the printer should be checked. 406*33262Ssklower * Unfortunately, this notice may persist through 407*33262Ssklower * the end of the print job, but this is no big deal. 408*33262Ssklower */ 409*33262Ssklower BackupStatus(".status","status"); 410*33262Ssklower 411*33262Ssklower if ((cpid = fork()) < 0) pexit(prog, THROW_AWAY); 412*33262Ssklower else if (cpid) {/* parent - sender */ 413*33262Ssklower VOIDC setjmp(sendint); 414*33262Ssklower 415*33262Ssklower if (intrup) { 416*33262Ssklower /* we only get here if there was an interrupt */ 417*33262Ssklower 418*33262Ssklower fprintf(stderr,"%s: abort (sending)\n",prog); 419*33262Ssklower VOIDC fflush(stderr); 420*33262Ssklower 421*33262Ssklower /* flush and restart output to printer, 422*33262Ssklower * send an abort (^C) request and wait for the job to end 423*33262Ssklower */ 424*33262Ssklower if (ioctl(fdsend, TIOCFLUSH,&flg) || ioctl(fdsend, TIOCSTART,&flg) 425*33262Ssklower || (write(fdsend, abortbuf, 1) != 1)) { 426*33262Ssklower RestoreStatus(); 427*33262Ssklower pexit(prog,THROW_AWAY); 428*33262Ssklower } 429*33262Ssklower debugp((stderr,"%s: sent interrupt - waiting\n",prog)); 430*33262Ssklower intrup = 0; 431*33262Ssklower goto donefile; /* sorry ewd! */ 432*33262Ssklower } 433*33262Ssklower 434*33262Ssklower VOIDC signal(SIGINT, intsend); 435*33262Ssklower VOIDC signal(SIGHUP, intsend); 436*33262Ssklower VOIDC signal(SIGQUIT, intsend); 437*33262Ssklower VOIDC signal(SIGTERM, intsend); 438*33262Ssklower VOIDC signal(SIGEMT, readynow); 439*33262Ssklower 440*33262Ssklower progress = oldprogress = 0; /* finite progress on sender */ 441*33262Ssklower getstatus = FALSE; /* prime the pump for fun FALSE; */ 442*33262Ssklower 443*33262Ssklower VOIDC signal(SIGALRM, salarm); /* sending phase alarm */ 444*33262Ssklower VOIDC alarm(SENDALARM); /* schedule an alarm/timeout */ 445*33262Ssklower 446*33262Ssklower /* loop, trying to send a ^T to get printer status 447*33262Ssklower * We will hang here (and post a message) if the printer 448*33262Ssklower * is unreachable. Eventually, we will succeed, the listener 449*33262Ssklower * will see the status report, signal us, and we will proceed 450*33262Ssklower */ 451*33262Ssklower 452*33262Ssklower cnt = 1; 453*33262Ssklower VOIDC setjmp(startstatus); 454*33262Ssklower 455*33262Ssklower while (TRUE) { 456*33262Ssklower if (goahead) break; 457*33262Ssklower debugp((stderr,"%s: get start status\n",prog)); 458*33262Ssklower VOIDC write(fdsend, statusbuf, 1); 459*33262Ssklower pause(); 460*33262Ssklower if (goahead) break; 461*33262Ssklower /* if we get here, we got an alarm */ 462*33262Ssklower ioctl(fdsend, TIOCFLUSH, &flg); 463*33262Ssklower ioctl(fdsend, TIOCSTART, &flg); 464*33262Ssklower sprintf(mybuf, "Not Responding for %d minutes", 465*33262Ssklower (cnt * SENDALARM+30)/60); 466*33262Ssklower Status(mybuf); 467*33262Ssklower alarm(SENDALARM); 468*33262Ssklower cnt++; 469*33262Ssklower } 470*33262Ssklower 471*33262Ssklower VOIDC signal(SIGEMT, emtdead); /* now EMTs mean printer died */ 472*33262Ssklower 473*33262Ssklower RestoreStatus(); 474*33262Ssklower debugp((stderr,"%s: printer responding\n",prog)); 475*33262Ssklower 476*33262Ssklower /* initial page accounting (BEFORE break page) */ 477*33262Ssklower if (doactng) { 478*33262Ssklower sprintf(mybuf, getpages, "\004"); 479*33262Ssklower VOIDC write(fdsend, mybuf, strlen(mybuf)); 480*33262Ssklower progress++; 481*33262Ssklower } 482*33262Ssklower 483*33262Ssklower /* initial break page ? */ 484*33262Ssklower if (BannerFirst) { 485*33262Ssklower SendBanner(); 486*33262Ssklower progress++; 487*33262Ssklower } 488*33262Ssklower 489*33262Ssklower /* ship the magic number! */ 490*33262Ssklower if ((!format) && (!reversing)) { 491*33262Ssklower VOIDC write(fdsend,magic,11); 492*33262Ssklower progress++; 493*33262Ssklower } 494*33262Ssklower 495*33262Ssklower /* now ship the rest of the file */ 496*33262Ssklower 497*33262Ssklower VOIDC alarm(SENDALARM); /* schedule an alarm */ 498*33262Ssklower 499*33262Ssklower while ((cnt = read(fdinput, mybuf, sizeof mybuf)) > 0) { 500*33262Ssklower /* VOIDC alarm(SENDALARM); /* we made progress, reset alarm */ 501*33262Ssklower if (intrup == TRUE) break; 502*33262Ssklower 503*33262Ssklower /* get status every other time */ 504*33262Ssklower if (getstatus) { 505*33262Ssklower VOIDC write(fdsend, statusbuf, 1); 506*33262Ssklower getstatus = FALSE; 507*33262Ssklower progress++; 508*33262Ssklower } 509*33262Ssklower mbp = mybuf; 510*33262Ssklower while ((cnt > 0) && ((wc = write(fdsend, mbp, cnt)) != cnt)) { 511*33262Ssklower /* this seems necessary but not sure why */ 512*33262Ssklower if (wc < 0) { 513*33262Ssklower fprintf(stderr,"%s: error writing to printer:\n",prog); 514*33262Ssklower perror(prog); 515*33262Ssklower RestoreStatus(); 516*33262Ssklower sleep(10); 517*33262Ssklower exit(TRY_AGAIN); 518*33262Ssklower } 519*33262Ssklower mbp += wc; 520*33262Ssklower cnt -= wc; 521*33262Ssklower progress++; 522*33262Ssklower } 523*33262Ssklower progress++; 524*33262Ssklower } 525*33262Ssklower if (cnt < 0) { 526*33262Ssklower fprintf(stderr,"%s: error reading from stdin: \n", prog); 527*33262Ssklower perror(prog); 528*33262Ssklower RestoreStatus(); 529*33262Ssklower sleep(10); 530*33262Ssklower exit(TRY_AGAIN); /* kill the listener? */ 531*33262Ssklower } 532*33262Ssklower 533*33262Ssklower 534*33262Ssklower donefile:; 535*33262Ssklower 536*33262Ssklower sendend = 1; 537*33262Ssklower 538*33262Ssklower VOIDC setjmp(dwait); 539*33262Ssklower 540*33262Ssklower if (sendend && !gotemt) { 541*33262Ssklower 542*33262Ssklower VOIDC signal(SIGEMT, emtdone); 543*33262Ssklower 544*33262Ssklower debugp((stderr,"%s: done sending\n",prog)); 545*33262Ssklower 546*33262Ssklower /* now send the PostScript EOF character */ 547*33262Ssklower VOIDC write(fdsend, eofbuf, 1); 548*33262Ssklower sendend = 0; 549*33262Ssklower progress++; 550*33262Ssklower 551*33262Ssklower VOIDC signal(SIGINT, intwait); 552*33262Ssklower VOIDC signal(SIGHUP, intwait); 553*33262Ssklower VOIDC signal(SIGQUIT, intwait); 554*33262Ssklower VOIDC signal(SIGTERM, intwait); 555*33262Ssklower 556*33262Ssklower VOIDC signal(SIGALRM, walarm); 557*33262Ssklower VOIDC alarm(WAITALARM); 558*33262Ssklower getstatus = TRUE; 559*33262Ssklower } 560*33262Ssklower 561*33262Ssklower /* wait to sync with listener EMT signal 562*33262Ssklower * to indicate it got an EOF from the printer 563*33262Ssklower */ 564*33262Ssklower while (TRUE) { 565*33262Ssklower if (gotemt) break; 566*33262Ssklower if (getstatus) { 567*33262Ssklower VOIDC write(fdsend, statusbuf, 1); 568*33262Ssklower getstatus = FALSE; 569*33262Ssklower } 570*33262Ssklower debugp((stderr,"waiting e%d i%d %d %d\n", 571*33262Ssklower gotemt,intrup,wpid,status)); 572*33262Ssklower wpid = wait(&status); 573*33262Ssklower if (wpid == -1) break; 574*33262Ssklower } 575*33262Ssklower 576*33262Ssklower VOIDC signal(SIGALRM, falarm); 577*33262Ssklower VOIDC alarm(WAITALARM); 578*33262Ssklower 579*33262Ssklower /* final break page ? */ 580*33262Ssklower if (BannerLast) { 581*33262Ssklower SendBanner(); 582*33262Ssklower progress++; 583*33262Ssklower } 584*33262Ssklower if (BannerFirst) VOIDC unlink(".banner"); 585*33262Ssklower 586*33262Ssklower /* final page accounting */ 587*33262Ssklower if (doactng) { 588*33262Ssklower sprintf(mybuf, getpages, ""); 589*33262Ssklower VOIDC write(fdsend, mybuf, strlen(mybuf)); 590*33262Ssklower progress++; 591*33262Ssklower } 592*33262Ssklower /* if we sent anything, finish it off */ 593*33262Ssklower if (BannerLast || doactng) { 594*33262Ssklower VOIDC write(fdsend, eofbuf, 1); 595*33262Ssklower progress++; 596*33262Ssklower } 597*33262Ssklower 598*33262Ssklower /* wait for listener to die */ 599*33262Ssklower VOIDC setjmp(dwait); 600*33262Ssklower while ((wpid = wait(&status)) > 0); 601*33262Ssklower VOIDC alarm(0); 602*33262Ssklower VOIDC signal(SIGINT, SIG_IGN); 603*33262Ssklower VOIDC signal(SIGHUP, SIG_IGN); 604*33262Ssklower VOIDC signal(SIGQUIT, SIG_IGN); 605*33262Ssklower VOIDC signal(SIGTERM, SIG_IGN); 606*33262Ssklower VOIDC signal(SIGEMT, SIG_IGN); 607*33262Ssklower debugp((stderr,"w2: s%lo p%d = p%d\n", status, wpid, cpid)); 608*33262Ssklower 609*33262Ssklower if (VerboseLog) { 610*33262Ssklower fprintf(stderr,"%s: end - %s",prog, 611*33262Ssklower (VOIDC time(&clock),ctime(&clock))); 612*33262Ssklower VOIDC fflush(stderr); 613*33262Ssklower } 614*33262Ssklower RestoreStatus(); 615*33262Ssklower exit(0); 616*33262Ssklower } 617*33262Ssklower else {/* child - listener */ 618*33262Ssklower register FILE *psin; 619*33262Ssklower register int r; 620*33262Ssklower 621*33262Ssklower char pbuf[BUFSIZ]; /* buffer for pagecount info */ 622*33262Ssklower char *pb; /* pointer for above */ 623*33262Ssklower int pc1, pc2; /* page counts before and after job */ 624*33262Ssklower int sc; /* pattern match count for sscanf */ 625*33262Ssklower char *outname; /* file name for job output */ 626*33262Ssklower int havejobout = FALSE; /* flag if jobout != stderr */ 627*33262Ssklower int ppid; /* parent process id */ 628*33262Ssklower 629*33262Ssklower VOIDC signal(SIGINT, SIG_IGN); 630*33262Ssklower VOIDC signal(SIGHUP, SIG_IGN); 631*33262Ssklower VOIDC signal(SIGQUIT, SIG_IGN); 632*33262Ssklower VOIDC signal(SIGTERM, SIG_IGN); 633*33262Ssklower VOIDC signal(SIGALRM, SIG_IGN); 634*33262Ssklower 635*33262Ssklower ppid = getppid(); 636*33262Ssklower 637*33262Ssklower /* get jobout from environment if there, otherwise use stderr */ 638*33262Ssklower if (((outname = envget("JOBOUTPUT")) == NULL) 639*33262Ssklower || ((jobout = fopen(outname,"w")) == NULL)) { 640*33262Ssklower jobout = stderr; 641*33262Ssklower } 642*33262Ssklower else havejobout = TRUE; 643*33262Ssklower 644*33262Ssklower pc1 = pc2 = -1; /* bogus initial values */ 645*33262Ssklower if ((psin = fdopen(fdlisten, "r")) == NULL) { 646*33262Ssklower RestoreStatus(); 647*33262Ssklower pexit(prog, THROW_AWAY); 648*33262Ssklower } 649*33262Ssklower 650*33262Ssklower /* listen for first status (idle?) */ 651*33262Ssklower pb = pbuf; 652*33262Ssklower *pb = '\0'; 653*33262Ssklower while (TRUE) { 654*33262Ssklower r = getc(psin); 655*33262Ssklower if (r == EOF) { 656*33262Ssklower fprintf(stderr, EOFerr, prog, "startup"); 657*33262Ssklower VOIDC fflush(stderr); 658*33262Ssklower sleep(20); /* printer may be coming up */ 659*33262Ssklower /* RestoreStatus(); */ 660*33262Ssklower /* exit(TRY_AGAIN); */ 661*33262Ssklower } 662*33262Ssklower if ((r & 0377) == '\n') break; /* newline */ 663*33262Ssklower *pb++ = r; 664*33262Ssklower } 665*33262Ssklower *pb = 0; 666*33262Ssklower if (strcmp(pbuf, "%%[ status: idle ]%%\r") != 0) { 667*33262Ssklower fprintf(stderr,"%s: initial status - %s\n",prog,pbuf); 668*33262Ssklower VOIDC fflush(stderr); 669*33262Ssklower } 670*33262Ssklower 671*33262Ssklower /* flush input state and signal sender that we heard something */ 672*33262Ssklower ioctl(fdlisten, TIOCFLUSH, &flg); 673*33262Ssklower 674*33262Ssklower VOIDC kill(ppid,SIGEMT); 675*33262Ssklower 676*33262Ssklower /* listen for first pagecount */ 677*33262Ssklower if (doactng) { 678*33262Ssklower pb = pbuf; 679*33262Ssklower *pb = '\0'; 680*33262Ssklower while (TRUE) { 681*33262Ssklower r = getc(psin); 682*33262Ssklower if (r == EOF) { 683*33262Ssklower fprintf(stderr, EOFerr, prog, "accounting1"); 684*33262Ssklower VOIDC fflush(stderr); 685*33262Ssklower RestoreStatus(); 686*33262Ssklower sleep(10); /* give interface a chance */ 687*33262Ssklower exit(TRY_AGAIN); 688*33262Ssklower } 689*33262Ssklower if ((r&0377) == 004) break; /* PS_EOF */ 690*33262Ssklower *pb++ = r; 691*33262Ssklower } 692*33262Ssklower *pb = '\0'; 693*33262Ssklower 694*33262Ssklower if (pb = FindPattern(pb, pbuf, "%%[ pagecount: ")) { 695*33262Ssklower sc = sscanf(pb, "%%%%[ pagecount: %d ]%%%%\r", &pc1); 696*33262Ssklower } 697*33262Ssklower if ((pb == NULL) || (sc != 1)) { 698*33262Ssklower fprintf(stderr, "%s: accounting error 1 (%s)\n", prog,pbuf); 699*33262Ssklower VOIDC fflush(stderr); 700*33262Ssklower } 701*33262Ssklower debugp((stderr,"%s: accounting 1 (%s)\n",prog,pbuf)); 702*33262Ssklower } 703*33262Ssklower 704*33262Ssklower /* listen for the user job */ 705*33262Ssklower while (TRUE) { 706*33262Ssklower r = getc(psin); 707*33262Ssklower if ((r&0377) == 004) break; /* PS_EOF */ 708*33262Ssklower else if (r == EOF) { 709*33262Ssklower VOIDC fclose(psin); 710*33262Ssklower fprintf(stderr, EOFerr, prog, "job"); 711*33262Ssklower VOIDC fflush(stderr); 712*33262Ssklower RestoreStatus(); 713*33262Ssklower VOIDC kill(ppid,SIGEMT); 714*33262Ssklower exit(THROW_AWAY); 715*33262Ssklower } 716*33262Ssklower GotChar(r); 717*33262Ssklower } 718*33262Ssklower 719*33262Ssklower /* let sender know we saw the end of the job */ 720*33262Ssklower /* sync - wait for sender to restart us */ 721*33262Ssklower 722*33262Ssklower debugp((stderr,"%s: listener saw eof, signaling\n",prog)); 723*33262Ssklower 724*33262Ssklower VOIDC kill(ppid,SIGEMT); 725*33262Ssklower 726*33262Ssklower /* now get final page count */ 727*33262Ssklower if (doactng) { 728*33262Ssklower pb = pbuf; 729*33262Ssklower *pb = '\0'; /* ignore the previous pagecount */ 730*33262Ssklower while (TRUE) { 731*33262Ssklower r = getc(psin); 732*33262Ssklower if (r == EOF) { 733*33262Ssklower fprintf(stderr, EOFerr, prog, "accounting2"); 734*33262Ssklower VOIDC fflush(stderr); 735*33262Ssklower RestoreStatus(); 736*33262Ssklower sleep(10); 737*33262Ssklower exit(THROW_AWAY); /* what else to do? */ 738*33262Ssklower } 739*33262Ssklower if ((r&0377) == 004) break; /* PS_EOF */ 740*33262Ssklower *pb++ = r; 741*33262Ssklower } 742*33262Ssklower *pb = '\0'; 743*33262Ssklower debugp((stderr,"%s: accounting 2 (%s)\n",prog,pbuf)); 744*33262Ssklower if (pb = FindPattern(pb, pbuf, "%%[ pagecount: ")) { 745*33262Ssklower sc = sscanf(pb, "%%%%[ pagecount: %d ]%%%%\r", &pc2); 746*33262Ssklower } 747*33262Ssklower if ((pb == NULL) || (sc != 1)) { 748*33262Ssklower fprintf(stderr, "%s: accounting error 2 (%s)\n", prog,pbuf); 749*33262Ssklower VOIDC fflush(stderr); 750*33262Ssklower } 751*33262Ssklower else if ((pc2 < pc1) || (pc1 < 0) || (pc2 < 0)) { 752*33262Ssklower fprintf(stderr,"%s: accounting error 3 %d %d\n", prog,pc1,pc2); 753*33262Ssklower VOIDC fflush(stderr); 754*33262Ssklower } 755*33262Ssklower else if (freopen(accountingfile, "a", stdout) != NULL) { 756*33262Ssklower printf("%7.2f\t%s:%s\n", (float)(pc2 - pc1), host, name); 757*33262Ssklower VOIDC fclose(stdout); 758*33262Ssklower } 759*33262Ssklower } 760*33262Ssklower 761*33262Ssklower /* all done -- let sender know */ 762*33262Ssklower if (havejobout) VOIDC fclose(jobout); 763*33262Ssklower VOIDC fclose(psin); 764*33262Ssklower exit(0); /* to parent */ 765*33262Ssklower } 766*33262Ssklower } 767*33262Ssklower 768*33262Ssklower /* send the file ".banner" */ 769*33262Ssklower private SendBanner() 770*33262Ssklower { 771*33262Ssklower register int banner; 772*33262Ssklower int cnt; 773*33262Ssklower char buf[BUFSIZ]; 774*33262Ssklower 775*33262Ssklower if ((banner = open(".banner",O_RDONLY|O_NDELAY,0)) < 0) return; 776*33262Ssklower while ((cnt = read(banner,buf,sizeof buf)) > 0) { 777*33262Ssklower VOIDC write(fdsend,buf,cnt); 778*33262Ssklower } 779*33262Ssklower VOIDC close(banner); 780*33262Ssklower } 781*33262Ssklower 782*33262Ssklower /* search backwards from p in start for patt */ 783*33262Ssklower private char *FindPattern(p, start, patt) 784*33262Ssklower char *p; 785*33262Ssklower char *start; 786*33262Ssklower char *patt; 787*33262Ssklower { 788*33262Ssklower int patlen; 789*33262Ssklower patlen = strlen(patt); 790*33262Ssklower 791*33262Ssklower p -= patlen; 792*33262Ssklower for (; p >= start; p--) { 793*33262Ssklower if (strncmp(p, patt, patlen) == 0) return(p); 794*33262Ssklower } 795*33262Ssklower return ((char *)NULL); 796*33262Ssklower } 797*33262Ssklower 798*33262Ssklower private GotChar(c) 799*33262Ssklower register int c; 800*33262Ssklower { 801*33262Ssklower static char linebuf[BUFSIZ]; 802*33262Ssklower static char *cp = linebuf; 803*33262Ssklower static enum State {normal, onep, twop, inmessage, 804*33262Ssklower close1, close2, close3, close4} st = normal; 805*33262Ssklower char *match, *last; 806*33262Ssklower 807*33262Ssklower switch (st) { 808*33262Ssklower case normal: 809*33262Ssklower if (c == '%') { 810*33262Ssklower st = onep; 811*33262Ssklower cp = linebuf; 812*33262Ssklower *cp++ = c; 813*33262Ssklower break; 814*33262Ssklower } 815*33262Ssklower putc(c,jobout); 816*33262Ssklower VOIDC fflush(jobout); 817*33262Ssklower break; 818*33262Ssklower case onep: 819*33262Ssklower if (c == '%') { 820*33262Ssklower st = twop; 821*33262Ssklower *cp++ = c; 822*33262Ssklower break; 823*33262Ssklower } 824*33262Ssklower putc('%',jobout); 825*33262Ssklower putc(c,jobout); 826*33262Ssklower VOIDC fflush(jobout); 827*33262Ssklower st = normal; 828*33262Ssklower break; 829*33262Ssklower case twop: 830*33262Ssklower if (c == '\[') { 831*33262Ssklower st = inmessage; 832*33262Ssklower *cp++ = c; 833*33262Ssklower break; 834*33262Ssklower } 835*33262Ssklower if (c == '\%') { 836*33262Ssklower putc('%',jobout); 837*33262Ssklower VOIDC fflush(jobout); 838*33262Ssklower /* don't do anything to cp */ 839*33262Ssklower break; 840*33262Ssklower } 841*33262Ssklower putc('%',jobout); 842*33262Ssklower putc('%',jobout); 843*33262Ssklower VOIDC fflush(jobout); 844*33262Ssklower st = normal; 845*33262Ssklower break; 846*33262Ssklower case inmessage: 847*33262Ssklower *cp++ = c; 848*33262Ssklower if (c == '\]') st = close1; 849*33262Ssklower break; 850*33262Ssklower case close1: 851*33262Ssklower *cp++ = c; 852*33262Ssklower switch (c) { 853*33262Ssklower case '%': st = close2; break; 854*33262Ssklower case '\]': st = close1; break; 855*33262Ssklower default: st = inmessage; break; 856*33262Ssklower } 857*33262Ssklower break; 858*33262Ssklower case close2: 859*33262Ssklower *cp++ = c; 860*33262Ssklower switch (c) { 861*33262Ssklower case '%': st = close3; break; 862*33262Ssklower case '\]': st = close1; break; 863*33262Ssklower default: st = inmessage; break; 864*33262Ssklower } 865*33262Ssklower break; 866*33262Ssklower case close3: 867*33262Ssklower *cp++ = c; 868*33262Ssklower switch (c) { 869*33262Ssklower case '\r': st = close4; break; 870*33262Ssklower case '\]': st = close1; break; 871*33262Ssklower default: st = inmessage; break; 872*33262Ssklower } 873*33262Ssklower break; 874*33262Ssklower case close4: 875*33262Ssklower *cp++ = c; 876*33262Ssklower switch(c) { 877*33262Ssklower case '\n': st = normal; break; 878*33262Ssklower case '\]': st = close1; break; 879*33262Ssklower default: st = inmessage; break; 880*33262Ssklower } 881*33262Ssklower if (st == normal) { 882*33262Ssklower /* parse complete message */ 883*33262Ssklower last = cp; 884*33262Ssklower *cp = 0; 885*33262Ssklower debugp((stderr,">>%s",linebuf)); 886*33262Ssklower if (match = FindPattern(cp, linebuf, " PrinterError: ")) { 887*33262Ssklower if (*(match-1) != ':') { 888*33262Ssklower fprintf(stderr,"%s",linebuf); 889*33262Ssklower VOIDC fflush(stderr); 890*33262Ssklower *(last-6) = 0; 891*33262Ssklower Status(match+15); 892*33262Ssklower } 893*33262Ssklower else { 894*33262Ssklower last = index(match,';'); 895*33262Ssklower *last = 0; 896*33262Ssklower Status(match+15); 897*33262Ssklower } 898*33262Ssklower } 899*33262Ssklower else if (match = FindPattern(cp, linebuf, " status: ")) { 900*33262Ssklower match += 9; 901*33262Ssklower if (strncmp(match,"idle",4) == 0) { 902*33262Ssklower /* we are hopelessly lost, get everyone to quit */ 903*33262Ssklower fprintf(stderr,"%s: ERROR: printer is idle, giving up!\n",prog); 904*33262Ssklower VOIDC fflush(stderr); 905*33262Ssklower VOIDC kill(getppid(),SIGKILL); /* will this work */ 906*33262Ssklower exit(THROW_AWAY); 907*33262Ssklower } 908*33262Ssklower else { 909*33262Ssklower /* one of: busy, waiting, printing, initializing */ 910*33262Ssklower /* clear status message */ 911*33262Ssklower RestoreStatus(); 912*33262Ssklower } 913*33262Ssklower } 914*33262Ssklower else { 915*33262Ssklower /* message not for us */ 916*33262Ssklower fprintf(jobout,"%s",linebuf); 917*33262Ssklower VOIDC fflush(jobout); 918*33262Ssklower st = normal; 919*33262Ssklower break; 920*33262Ssklower } 921*33262Ssklower } 922*33262Ssklower break; 923*33262Ssklower default: 924*33262Ssklower fprintf(stderr,"bad case;\n"); 925*33262Ssklower } 926*33262Ssklower return; 927*33262Ssklower } 928*33262Ssklower 929*33262Ssklower /* backup "status" message file in ".status", 930*33262Ssklower * in case there is a PrinterError 931*33262Ssklower */ 932*33262Ssklower 933*33262Ssklower private BackupStatus(file1, file2) 934*33262Ssklower char *file1, *file2; 935*33262Ssklower { 936*33262Ssklower register int fd1, fd2; 937*33262Ssklower char buf[BUFSIZ]; 938*33262Ssklower int cnt; 939*33262Ssklower 940*33262Ssklower VOIDC umask(0); 941*33262Ssklower fd1 = open(file1, O_WRONLY|O_CREAT, 0664); 942*33262Ssklower if ((fd1 < 0) || (flock(fd1,LOCK_EX) < 0)) { 943*33262Ssklower VOIDC unlink(file1); 944*33262Ssklower VOIDC flock(fd1,LOCK_UN); 945*33262Ssklower VOIDC close(fd1); 946*33262Ssklower fd1 = open(file1, O_WRONLY|O_CREAT, 0664); 947*33262Ssklower } 948*33262Ssklower if ((fd1 < 0) || (flock(fd1,LOCK_EX) <0)) { 949*33262Ssklower fprintf(stderr, "%s: writing %s:\n",prog,file1); 950*33262Ssklower perror(prog); 951*33262Ssklower VOIDC close(fd1); 952*33262Ssklower return; 953*33262Ssklower } 954*33262Ssklower VOIDC ftruncate(fd1,0); 955*33262Ssklower if ((fd2 = open(file2, O_RDONLY,0)) < 0) { 956*33262Ssklower fprintf(stderr, "%s: error reading %s:\n", prog, file2); 957*33262Ssklower perror(prog); 958*33262Ssklower VOIDC close(fd1); 959*33262Ssklower return; 960*33262Ssklower } 961*33262Ssklower cnt = read(fd2,buf,BUFSIZ); 962*33262Ssklower VOIDC write(fd1,buf,cnt); 963*33262Ssklower VOIDC flock(fd1,LOCK_UN); 964*33262Ssklower VOIDC close(fd1); 965*33262Ssklower VOIDC close(fd2); 966*33262Ssklower } 967*33262Ssklower 968*33262Ssklower /* restore the "status" message from the backed-up ".status" copy */ 969*33262Ssklower private RestoreStatus() { 970*33262Ssklower BackupStatus("status",".status"); 971*33262Ssklower } 972*33262Ssklower 973*33262Ssklower /* report PrinterError via "status" message file */ 974*33262Ssklower private Status(msg) 975*33262Ssklower register char *msg; 976*33262Ssklower { 977*33262Ssklower register int fd; 978*33262Ssklower char msgbuf[100]; 979*33262Ssklower 980*33262Ssklower if ((fd = open("status",O_WRONLY|O_CREAT,0664)) < 0) return; 981*33262Ssklower VOIDC ftruncate(fd,0); 982*33262Ssklower sprintf(msgbuf,"Printer Error: may need attention! (%s)\n\0",msg); 983*33262Ssklower VOIDC write(fd,msgbuf,strlen(msgbuf)); 984*33262Ssklower VOIDC close(fd); 985*33262Ssklower } 986*33262Ssklower 987*33262Ssklower /* sending phase alarm handler for sender */ 988*33262Ssklower 989*33262Ssklower private VOID salarm() { 990*33262Ssklower 991*33262Ssklower debugp((stderr,"%s: AS %d %d %d\n",prog,oldprogress,progress,getstatus)); 992*33262Ssklower 993*33262Ssklower /* if progress != oldprogress, we made some progress (sent something) 994*33262Ssklower * else, we had two alarms without sending anything... 995*33262Ssklower * It may be that a PrinterError has us stopped, or we are computing 996*33262Ssklower * for a long time (forever?) -- printer jobtimeout may help here 997*33262Ssklower * in any case, all we do is set the flag to get status... 998*33262Ssklower * this will help us clear printererror notification 999*33262Ssklower */ 1000*33262Ssklower 1001*33262Ssklower oldprogress = progress; 1002*33262Ssklower getstatus = TRUE; 1003*33262Ssklower 1004*33262Ssklower /* reset the alarm and return */ 1005*33262Ssklower VOIDC alarm(SENDALARM); 1006*33262Ssklower return; 1007*33262Ssklower } 1008*33262Ssklower 1009*33262Ssklower /* waiting phase alarm handler for sender */ 1010*33262Ssklower 1011*33262Ssklower private VOID walarm() { 1012*33262Ssklower static int acount = 0; 1013*33262Ssklower 1014*33262Ssklower debugp((stderr,"%s: WA %d %d %d %d\n", 1015*33262Ssklower prog,acount,oldprogress,progress,getstatus)); 1016*33262Ssklower 1017*33262Ssklower if ((oldprogress != progress) || (acount == 4)) { 1018*33262Ssklower getstatus = TRUE; 1019*33262Ssklower acount = 0; 1020*33262Ssklower oldprogress = progress; 1021*33262Ssklower } 1022*33262Ssklower else acount++; 1023*33262Ssklower 1024*33262Ssklower /* reset alarm */ 1025*33262Ssklower VOIDC alarm(WAITALARM); 1026*33262Ssklower 1027*33262Ssklower /* return to wait loop */ 1028*33262Ssklower longjmp(dwait, 0); 1029*33262Ssklower } 1030*33262Ssklower 1031*33262Ssklower /* final phase alarm handler for sender */ 1032*33262Ssklower 1033*33262Ssklower private VOID falarm() { 1034*33262Ssklower 1035*33262Ssklower debugp((stderr,"%s: FA %d %d %d\n",prog,oldprogress,progress,getstatus)); 1036*33262Ssklower 1037*33262Ssklower /* no reason to count progress, just get status */ 1038*33262Ssklower if (!intrup) { 1039*33262Ssklower VOIDC write(fdsend, statusbuf, 1); 1040*33262Ssklower } 1041*33262Ssklower getstatus = FALSE; 1042*33262Ssklower 1043*33262Ssklower /* reset alarm */ 1044*33262Ssklower VOIDC alarm(WAITALARM); 1045*33262Ssklower return; 1046*33262Ssklower } 1047*33262Ssklower 1048*33262Ssklower /* initial interrupt handler - before communications begin, so 1049*33262Ssklower * nothing to be sent to printer 1050*33262Ssklower */ 1051*33262Ssklower private VOID intinit() { 1052*33262Ssklower long clock; 1053*33262Ssklower 1054*33262Ssklower /* get rid of banner file */ 1055*33262Ssklower VOIDC unlink(".banner"); 1056*33262Ssklower 1057*33262Ssklower fprintf(stderr,"%s: abort (during setup)\n",prog); 1058*33262Ssklower VOIDC fflush(stderr); 1059*33262Ssklower 1060*33262Ssklower /* these next two may be too cautious */ 1061*33262Ssklower VOIDC kill(0,SIGINT); 1062*33262Ssklower while (wait((union wait *) 0) > 0); 1063*33262Ssklower 1064*33262Ssklower if (VerboseLog) { 1065*33262Ssklower fprintf (stderr, "%s: end - %s", prog, (time(&clock), ctime(&clock))); 1066*33262Ssklower VOIDC fflush(stderr); 1067*33262Ssklower } 1068*33262Ssklower 1069*33262Ssklower exit(THROW_AWAY); 1070*33262Ssklower } 1071*33262Ssklower 1072*33262Ssklower /* interrupt during sending phase to sender process */ 1073*33262Ssklower 1074*33262Ssklower private VOID intsend() { 1075*33262Ssklower /* set flag */ 1076*33262Ssklower intrup = TRUE; 1077*33262Ssklower longjmp(sendint, 0); 1078*33262Ssklower } 1079*33262Ssklower 1080*33262Ssklower /* interrupt during waiting phase to sender process */ 1081*33262Ssklower 1082*33262Ssklower private VOID intwait() { 1083*33262Ssklower 1084*33262Ssklower intrup = TRUE; 1085*33262Ssklower 1086*33262Ssklower fprintf(stderr,"%s: abort (waiting)\n",prog); 1087*33262Ssklower VOIDC fflush(stderr); 1088*33262Ssklower if (ioctl(fdsend, TIOCFLUSH, &flg) || ioctl(fdsend, TIOCSTART, &flg) 1089*33262Ssklower || (write(fdsend, abortbuf, 1) != 1)) { 1090*33262Ssklower fprintf(stderr, "%s: error in ioctl(fdsend):\n", prog); 1091*33262Ssklower perror(prog); 1092*33262Ssklower } 1093*33262Ssklower 1094*33262Ssklower /* VOIDC alarm(2); /* force an alarm soon to get us out of wait! ? */ 1095*33262Ssklower longjmp(dwait, 0); 1096*33262Ssklower } 1097*33262Ssklower 1098*33262Ssklower /* EMT for reverse filter, avoid printer timeout at the expense 1099*33262Ssklower * of performance (sigh) 1100*33262Ssklower */ 1101*33262Ssklower 1102*33262Ssklower private VOID reverseready() { 1103*33262Ssklower revdone = TRUE; 1104*33262Ssklower longjmp(waitonreverse, 0); 1105*33262Ssklower } 1106*33262Ssklower 1107*33262Ssklower /* EMT on startup to sender -- signalled by listener after first status 1108*33262Ssklower * message received 1109*33262Ssklower */ 1110*33262Ssklower 1111*33262Ssklower private VOID readynow() { 1112*33262Ssklower goahead = TRUE; 1113*33262Ssklower longjmp(startstatus, 0); 1114*33262Ssklower } 1115*33262Ssklower 1116*33262Ssklower /* EMT on sending phase, hard EOF printer died! */ 1117*33262Ssklower private VOID emtdead() { 1118*33262Ssklower VOIDC alarm(0); 1119*33262Ssklower exit(THROW_AWAY); 1120*33262Ssklower } 1121*33262Ssklower 1122*33262Ssklower /* EMT during waiting phase -- listener saw an EOF (^D) from printer */ 1123*33262Ssklower 1124*33262Ssklower private VOID emtdone() { 1125*33262Ssklower VOIDC alarm(0); 1126*33262Ssklower gotemt = TRUE; 1127*33262Ssklower longjmp(dwait, 0); 1128*33262Ssklower } 1129