diff options
author | rsc <devnull@localhost> | 2005-08-31 02:18:29 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-08-31 02:18:29 +0000 |
commit | 262ecfed9f7e39811f34517d82e848b8ec20f863 (patch) | |
tree | b9947441be3e7b6a3d7c5e944854591e1b027bfb /src/cmd/lp/lpsend.c | |
parent | 2863ba101f0c9fec34756948e263cd534a3634ee (diff) | |
download | plan9port-262ecfed9f7e39811f34517d82e848b8ec20f863.tar.gz plan9port-262ecfed9f7e39811f34517d82e848b8ec20f863.tar.bz2 plan9port-262ecfed9f7e39811f34517d82e848b8ec20f863.zip |
Initial lp.
Diffstat (limited to 'src/cmd/lp/lpsend.c')
-rw-r--r-- | src/cmd/lp/lpsend.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/src/cmd/lp/lpsend.c b/src/cmd/lp/lpsend.c new file mode 100644 index 00000000..4893f452 --- /dev/null +++ b/src/cmd/lp/lpsend.c @@ -0,0 +1,341 @@ +#ifdef plan9 + +#include <u.h> +#include <libc.h> +#define stderr 2 + +#define RDNETIMEOUT 60000 +#define WRNETIMEOUT 60000 + +#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); + return; +} + +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)); + return; +} + +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 int tindx = 0; + char tmpf[20]; + int tmpfd; + + sprint(tmpf, "/var/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; + int datafd; + +#ifndef plan9 + + void (*oldhandler)(); + +#endif + + devdir = nil; + /* make connection */ + if (argc != 2) { + fprint(stderr, "usage: %s network!destination!service\n", argv[0]); + exits("incorrect number of arguments"); + } + + /* 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 %s\n", devdir); + perror("dial"); + 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 while 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 while 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 + +} |