diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/lp/lpdaemon.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/lp/lpdaemon.c')
-rwxr-xr-x | sys/src/cmd/lp/lpdaemon.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/sys/src/cmd/lp/lpdaemon.c b/sys/src/cmd/lp/lpdaemon.c new file mode 100755 index 000000000..b646a005b --- /dev/null +++ b/sys/src/cmd/lp/lpdaemon.c @@ -0,0 +1,447 @@ +#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[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]); +} + +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); +} |