123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <time.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- /* 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<b)?a:b)
- #define CPYFIELD(src, dst) { while (*(src)!=' ' && *(src)!='\t' && *(src)!='\r' && *(src)!='\n' && *(src)!='\0') *(dst)++ = *(src)++; }
- #define ACK() write(1, "", 1)
- #define NAK() write(1, "\001", 1)
- #define LNBFSZ 4096
- unsigned char lnbuf[LNBFSZ];
- #define RDSIZE 512
- unsigned char jobbuf[RDSIZE];
- int datafd[400], cntrlfd = -1;
- int dbgstate = 0;
- char *dbgstrings[] = {
- "",
- "sendack1",
- "send",
- "rcvack",
- "sendack2",
- "done"
- };
- void
- error(char *s1, ...)
- {
- FILE *fp;
- long thetime;
- char *chartime;
- va_list ap;
- char *args[8];
- int argno = 0;
- if((fp=fopen(LPDAEMONLOG, "a"))==NULL) {
- fprintf(stderr, "cannot open %s in append mode\n", LPDAEMONLOG);
- return;
- }
- time(&thetime);
- chartime = ctime(&thetime);
- fprintf(fp, "%.15s [%5.5d] ", &(chartime[4]), getpid());
- va_start(ap, s1);
- while((args[argno++] = va_arg(ap, char*)) && argno<8)
- ;
- va_end(ap);
- fprintf(fp, s1, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
- fclose(fp);
- }
- void
- forklp(int inputfd)
- {
- int i, cpid;
- unsigned char *bp, *cp;
- unsigned char logent[LNBFSZ];
- /* log this call to lp */
- cp = logent;
- for (i=1; i<argcnt; i++) {
- bp = argvals[i];
- if (cp+strlen((const char *)bp)+1 < logent+LNBFSZ-1) {
- CPYFIELD(bp, cp);
- *cp++ = ' ';
- }
- }
- *--cp = '\n';
- *++cp = '\0';
- error((const char *)logent);
- switch((cpid=fork())){
- case -1:
- error("fork error\n");
- exit(2);
- case 0:
- if (inputfd != 0)
- dup2(inputfd, 0);
- dup2(1, 2);
- lseek(0, 0L, 0);
- execvp(LP, (const char **)argvals);
- error("exec failed\n");
- exit(3);
- default:
- while(wait((int *)0) != cpid)
- ;
- }
- }
- int
- tempfile(void)
- {
- static tindx = 0;
- char tmpf[sizeof(TMPDIR)+64];
- int crtfd, tmpfd;
- sprintf(tmpf, "%s/lp%d.%d", TMPDIR, getpid(), tindx++);
- if((crtfd=creat(tmpf, 0666)) < 0) {
- error("cannot create temp file %s\n", tmpf);
- NAK();
- exit(3);
- }
- if((tmpfd=open(tmpf, 2)) < 0) {
- error("cannot open temp file %s\n", tmpf);
- NAK();
- exit(3);
- }
- close(crtfd);
- unlink(tmpf); /* comment out for debugging */
- return(tmpfd);
- }
- int
- readfile(int outfd, int bsize)
- {
- int rv;
- dbgstate = 1;
- alarm(60);
- ACK();
- dbgstate = 2;
- for(; bsize > 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[NAMELEN] = '\0';
- break;
- case 'P':
- if (ap[1] == '\0')
- strncpy(info.user, "unknown", NAMELEN);
- else
- strncpy(info.user, (const char *)&ap[1], NAMELEN);
- info.user[NAMELEN] = '\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<rv;i++)
- forklp(datafd[i]);
- }
- exit(0);
- case '\005':
- bp++; /* drop the ctrl character from the input */
- argvals[argcnt++] = cp;
- *cp++ = '-'; *cp++ = 'k'; *cp++ = '\0'; /* -k */
- argvals[argcnt++] = cp;
- *cp++ = '-'; *cp++ = 'd'; /* -d */
- CPYFIELD(bp, cp); /* printer */
- *cp++ = '\0';
- argvals[argcnt++] = cp;
- *cp++ = '-'; ap = cp; *cp++ = 'u'; /* -u */
- CPYFIELD(bp, cp); /* username */
- /* deal with bug in lprng where the username is not supplied
- */
- if (ap == (cp-1)) {
- ap = (unsigned char *)"none";
- CPYFIELD(ap, cp);
- }
- *cp++ = '\0';
- datafd[0] = tempfile();
- blen = strlen((const char *)bp);
- if (write(datafd[0], bp, blen) != blen) {
- error("write error\n");
- exit(6);
- }
- if (write(datafd[0], "\n", 1) != 1) {
- error("write error\n");
- exit(6);
- }
- break;
- default:
- /* otherwise get my lp arguments */
- do {
- /* move to next non-white space */
- while (*bp==' '||*bp=='\t')
- ++bp;
- if (*bp=='\n') continue;
- /* only accept arguments beginning with -
- * this is done to prevent the printing of
- * local files from the destination host
- */
- if (*bp=='-') {
- argvals[argcnt++] = cp;
- saveflg = 1;
- } else
- saveflg = 0;
- /* move to next white space copying text to argument buffer */
- while (*bp!=' ' && *bp!='\t' && *bp!='\n'
- && *bp!='\0') {
- *cp = *bp++;
- cp += saveflg;
- }
- *cp = '\0';
- cp += saveflg;
- } while (*bp!='\n' && *bp!='\0');
- if (readline(0) < 0) exit(7);
- datafd[0] = tempfile();
- if(readfile(datafd[0], atoi((const char *)lnbuf)) < 0) {
- error("readfile failed\n");
- exit(8);
- }
- }
- forklp(datafd[0]);
- exit(0);
- }
|