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/lpsend.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/lp/lpsend.c')
-rwxr-xr-x | sys/src/cmd/lp/lpsend.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/sys/src/cmd/lp/lpsend.c b/sys/src/cmd/lp/lpsend.c new file mode 100755 index 000000000..8b8bd24e7 --- /dev/null +++ b/sys/src/cmd/lp/lpsend.c @@ -0,0 +1,320 @@ +#ifdef plan9 + +#include <u.h> +#include <libc.h> + +enum { + stderr = 2, + RDNETIMEOUT = 30*60*1000, + WRNETIMEOUT = RDNETIMEOUT, +}; +#else + +/* not for plan 9 */ +#include <stdio.h> +#include <errno.h> +#include <time.h> +#include <fcntl.h> +#include <signal.h> + +#define create creat +#define seek lseek +#define fprint fprintf +#define sprint sprintf +#define exits exit + +#define ORDWR O_RDWR +#define OTRUNC O_TRUNC +#define ORCLOSE 0 + +#define RDNETIMEOUT 60 +#define WRNETIMEOUT 60 + +#endif + +#define MIN(a,b) ((a<b)?a:b) + +#define ACK(a) write(a, "", 1) +#define NAK(a) write(a, "\001", 1) + +#define LPDAEMONLOG "/tmp/lpdaemonl" + +#define LNBFSZ 4096 +char lnbuf[LNBFSZ]; +int dbgstate = 0; +char *dbgstrings[] = { + "", + "rcvack1", + "send", + "rcvack2", + "response", + "done" +}; + +#ifdef plan9 + +void +error(int level, char *s1, ...) +{ + va_list ap; + long thetime; + char *chartime; + char *args[8]; + int argno = 0; + + if (level == 0) { + time(&thetime); + chartime = ctime(thetime); + fprint(stderr, "%.15s ", &(chartime[4])); + } + va_start(ap, s1); + while(args[argno++] = va_arg(ap, char*)) + ; + va_end(ap); + fprint(stderr, s1, *args); +} + +int +alarmhandler(void *foo, char *note) { + USED(foo); + if(strcmp(note, "alarm")==0) { + fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); + return(1); + } else return(0); +} + +#else + +void +error(int level, char *s1, ...) +{ + time_t thetime; + char *chartime; + + if (level == 0) { + time(&thetime); + chartime = ctime(&thetime); + fprintf(stderr, "%.15s ", &(chartime[4])); + } + fprintf(stderr, s1, &s1 + 1); +} + +void +alarmhandler() { + fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); +} + +#endif + +/* get a line from inpfd using nonbuffered input. The line is truncated if it is too + * long for the buffer. The result is left in lnbuf and the number of characters + * read in is returned. + */ +int +readline(int inpfd) +{ + register char *ap; + register int i; + + ap = lnbuf; + i = 0; + do { + if (read(inpfd, ap, 1) != 1) { + error(0, "read error in readline, fd=%d\n", inpfd); + break; + } + } while ((++i < LNBFSZ - 2) && *ap++ != '\n'); + if (i == LNBFSZ - 2) { + *ap = '\n'; + i++; + } + *ap = '\0'; + return(i); +} + +#define RDSIZE 512 +char jobbuf[RDSIZE]; + +int +pass(int inpfd, int outfd, int bsize) +{ + int bcnt = 0; + int rv = 0; + + for(bcnt=bsize; bcnt > 0; bcnt -= rv) { + alarm(WRNETIMEOUT); /* to break hanging */ + if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) { + error(0, "read error during pass, %d remaining\n", bcnt); + break; + } else if((write(outfd, jobbuf, rv)) != rv) { + error(0, "write error during pass, %d remaining\n", bcnt); + break; + } + } + alarm(0); + return(bcnt); +} + +/* get whatever stdin has and put it into the temporary file. + * return the file size. + */ +int +prereadfile(int inpfd) +{ + int rv, bsize; + + bsize = 0; + do { + if((rv=read(0, jobbuf, RDSIZE))<0) { + error(0, "read error while making temp file\n"); + exits("read error while making temp file"); + } else if((write(inpfd, jobbuf, rv)) != rv) { + error(0, "write error while making temp file\n"); + exits("write error while making temp file"); + } + bsize += rv; + } while (rv!=0); + return(bsize); +} + +int +tempfile(void) +{ + static tindx = 0; + char tmpf[20]; + int tmpfd; + + sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++); + if((tmpfd=create(tmpf, +#ifdef plan9 + ORDWR|OTRUNC, +#endif + 0666)) < 0) { + error(0, "cannot create temp file %s\n", tmpf); + exits("cannot create temp file"); + } + close(tmpfd); + if((tmpfd=open(tmpf, ORDWR +#ifdef plan9 + |ORCLOSE|OTRUNC +#endif + )) < 0) { + error(0, "cannot open temp file %s\n", tmpf); + exits("cannot open temp file"); + } + return(tmpfd); +} + +int +recvACK(int netfd) +{ + int rv; + + *jobbuf = '\0'; + alarm(RDNETIMEOUT); + if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') { + error(0, "failed to receive ACK, "); + if (*jobbuf == '\0') + error(1, "read failed\n"); + else + error(1, "received <0x%x> instead\n", *jobbuf); + rv = 0; + } else rv = 1; + alarm(0); + return(rv); +} + +void +main(int argc, char *argv[]) +{ + char *devdir; + int i, rv, netfd, bsize, datafd; +#ifndef plan9 + void (*oldhandler)(); +#endif + + /* make connection */ + if (argc != 2) { + fprint(stderr, "usage: %s network!destination!service\n", + argv[0]); + exits("usage"); + } + + /* read options line from stdin into lnbuf */ + i = readline(0); + + /* read stdin into tempfile to get size */ + datafd = tempfile(); + bsize = prereadfile(datafd); + + /* network connection is opened after data is in to avoid timeout */ + if ((netfd = dial(argv[1], 0, 0, 0)) < 0) { + fprint(stderr, "dialing "); + perror(argv[1]); + exits("can't dial"); + } + + /* write out the options we read above */ + if (write(netfd, lnbuf, i) != i) { + error(0, "write error while sending options\n"); + exits("write error sending options"); + } + + /* send the size of the file to be sent */ + sprint(lnbuf, "%d\n", bsize); + i = strlen(lnbuf); + if ((rv=write(netfd, lnbuf, i)) != i) { + perror("write error while sending size"); + error(0, "write returned %d\n", rv); + exits("write error sending size"); + } + + if (seek(datafd, 0L, 0) < 0) { + error(0, "error seeking temp file\n"); + exits("seek error"); + } + /* mirror performance in readfile() in lpdaemon */ + +#ifdef plan9 + atnotify(alarmhandler, 1); +#else + oldhandler = signal(SIGALRM, alarmhandler); +#endif + + dbgstate = 1; + if(!recvACK(netfd)) { + error(0, "failed to receive ACK before sending data\n"); + exits("recv ack1 failed"); + } + dbgstate = 2; + if ((i=pass(datafd, netfd, bsize)) != 0) { + NAK(netfd); + error(0, "failed to send %d bytes\n", i); + exits("send data failed"); + } + ACK(netfd); + dbgstate = 3; + if(!recvACK(netfd)) { + error(0, "failed to receive ACK after sending data\n"); + exits("recv ack2 failed"); + } + + /* get response, as from lp -q */ + dbgstate = 4; + while((rv=read(netfd, jobbuf, RDSIZE)) > 0) { + if((write(1, jobbuf, rv)) != rv) { + error(0, "write error while sending to stdout\n"); + exits("write error while sending to stdout"); + } + } + dbgstate = 5; + +#ifdef plan9 + atnotify(alarmhandler, 0); + /* close down network connections and go away */ + exits(""); +#else + signal(SIGALRM, oldhandler); + exit(0); +#endif +} |