#include #include #include #include #include #include #include #include #include #include #include /* for Plan 9 */ #ifdef PLAN9 #define LP "/bin/lp" #define TMPDIR "/sys/lib/lp/tmp" #define LPDAEMONLOG "/sys/lib/lp/log/lpdaemonl" #endif /* for Tenth Edition systems */ #ifdef V10 #define LP "/usr/bin/lp" #define TMPDIR "/tmp" #define LPDAEMONLOG "/tmp/lpdaemonl" #endif /* for System V or BSD systems */ #if defined(SYSV) || defined(BSD) #define LP "/v/bin/lp" #define TMPDIR "/tmp" #define LPDAEMONLOG "/tmp/lpdaemonl" #endif #define ARGSIZ 4096 #define NAMELEN 30 unsigned char argvstr[ARGSIZ]; /* arguments after parsing */ unsigned char *argvals[ARGSIZ/2+1]; /* pointers to arguments after parsing */ int ascnt = 0, argcnt = 0; /* number of arguments parsed */ /* for 'stuff' gleened from lpr cntrl file */ struct jobinfo { char user[NAMELEN+1]; char host[NAMELEN+1]; } *getjobinfo(); #define MIN(a,b) ((a 0; bsize -= rv) { alarm(60); if((rv=read(0, jobbuf, MIN(bsize,RDSIZE))) < 0) { error("error reading input, %d unread\n", bsize); exit(4); } else if (rv == 0) { error("connection closed prematurely\n"); exit(4); } else if((write(outfd, jobbuf, rv)) != rv) { error("error writing temp file, %d unread\n", bsize); exit(5); } } dbgstate = 3; alarm(60); if (((rv=read(0, jobbuf, 1))==1) && (*jobbuf=='\0')) { alarm(60); ACK(); dbgstate = 4; alarm(0); return(outfd); } alarm(0); error("received bad status <%d> from sender\n", *jobbuf); error("rv=%d\n", rv); NAK(); return(-1); } /* reads a line from the input into lnbuf * if there is no error, it returns * the number of characters in the buffer * if there is an error and there where characters * read, it returns the negative value of the * number of characters read * if there is an error and no characters were read, * it returns the negative value of 1 greater than * the size of the line buffer */ int readline(int inpfd) { unsigned char *ap; int i, rv; ap = lnbuf; lnbuf[0] = '\0'; i = 0; alarm(60); do { rv = read(inpfd, ap, 1); } while (rv==1 && ++i && *ap != '\n' && ap++ && (i < LNBFSZ - 2)); alarm(0); if (i != 0 && *ap != '\n') { *++ap = '\n'; i++; } *++ap = '\0'; if (rv < 0) { error("read error; lost connection\n"); if (i==0) i = -(LNBFSZ+1); else i = -i; } return(i); } int getfiles(void) { unsigned char *ap; int filecnt, bsize, rv; filecnt = 0; /* get a line, hopefully containing a ctrl char, size, and name */ for(;;) { ap = lnbuf; if ((rv=readline(0)) < 0) NAK(); if (rv <= 0) { return(filecnt); } switch(*ap++) { case '\1': /* cleanup - data sent was bad (whatever that means) */ break; case '\2': /* read control file */ bsize = atoi((const char *)ap); cntrlfd = tempfile(); if (readfile(cntrlfd, bsize) < 0) { close(cntrlfd); NAK(); return(0); } break; case '\3': /* read data file */ bsize = atoi((const char *)ap); datafd[filecnt] = tempfile(); if (readfile(datafd[filecnt], bsize) < 0) { close(datafd[filecnt]); NAK(); return(0); } filecnt++; break; default: error("protocol error <%d>\n", *(ap-1)); NAK(); } } return(filecnt); } struct jobinfo * getjobinfo(int fd) { unsigned char *ap; int rv; static struct jobinfo info; if (fd < 0) error("getjobinfo: bad file descriptor\n"); if (lseek(fd, 0L, 0) < 0) { error("error seeking in temp file\n"); exit(7); } /* the following strings should be < NAMELEN or else they will not * be null terminated. */ strncpy(info.user, "daemon", NAMELEN); strncpy(info.host, "nowhere", NAMELEN); /* there may be a space after the name and host. It will be filtered out * by CPYFIELD. */ while ((rv=readline(fd)) > 0) { ap = lnbuf; ap[rv-1] = '\0'; /* remove newline from string */ switch (*ap) { case 'H': if (ap[1] == '\0') strncpy(info.host, "unknown", NAMELEN); else strncpy(info.host, (const char *)&ap[1], NAMELEN); info.host[strlen(info.host)] = '\0'; break; case 'P': if (ap[1] == '\0') strncpy(info.user, "unknown", NAMELEN); else strncpy(info.user, (const char *)&ap[1], NAMELEN); info.user[strlen(info.user)] = '\0'; break; } } return(&info); } void alarmhandler(int sig) { signal(sig, alarmhandler); error("alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); } void main() { unsigned char *ap, *bp, *cp, *savbufpnt; int i, blen, rv, saveflg, savargcnt; struct jobinfo *jinfop; signal(SIGHUP, SIG_IGN); signal(SIGALRM, alarmhandler); cp = argvstr; /* setup argv[0] for exec */ argvals[argcnt++] = cp; for (bp = (unsigned char *)LP, i = 0; (*bp != '\0') && (i < ARGSIZ-1); *cp++ = *bp++, i++); *cp++ = '\0'; /* get the first line sent and parse it as arguments for lp */ if ((rv=readline(0)) < 0) exit(1); bp = lnbuf; /* setup the remaining arguments */ /* check for BSD style request */ /* ^A, ^B, ^C, ^D, ^E (for BSD lpr) */ switch (*bp) { case '\001': case '\003': case '\004': bp++; /* drop the ctrl character from the input */ argvals[argcnt++] = cp; *cp++ = '-'; *cp++ = 'q'; *cp++ = '\0'; /* -q */ argvals[argcnt++] = cp; *cp++ = '-'; *cp++ = 'd'; /* -d */ CPYFIELD(bp, cp); /* printer */ *cp++ = '\0'; break; case '\002': bp++; /* drop the ctrl character from the input */ argvals[argcnt++] = cp; *cp++ = '-'; *cp++ = 'd'; /* -d */ CPYFIELD(bp, cp); /* printer */ *cp++ = '\0'; ACK(); savargcnt = argcnt; savbufpnt = cp; while ((rv=getfiles())) { jinfop = getjobinfo(cntrlfd); close(cntrlfd); argcnt = savargcnt; cp = savbufpnt; argvals[argcnt++] = cp; *cp++ = '-'; *cp++ = 'M'; /* -M */ bp = (unsigned char *)jinfop->host; CPYFIELD(bp, cp); /* host name */ *cp++ = '\0'; argvals[argcnt++] = cp; *cp++ = '-'; *cp++ = 'u'; /* -u */ bp = (unsigned char *)jinfop->user; CPYFIELD(bp, cp); /* user name */ *cp++ = '\0'; for(i=0;i