From e5888a1ffdae813d7575f5fb02275c6bb07e5199 Mon Sep 17 00:00:00 2001 From: Taru Karttunen Date: Wed, 30 Mar 2011 15:46:40 +0300 Subject: Import sources from 2011-03-30 iso image --- sys/src/cmd/postscript/tcpostio/dial.c | 109 ++++++ sys/src/cmd/postscript/tcpostio/mkfile | 16 + sys/src/cmd/postscript/tcpostio/tcpostio.c | 534 +++++++++++++++++++++++++++++ 3 files changed, 659 insertions(+) create mode 100755 sys/src/cmd/postscript/tcpostio/dial.c create mode 100755 sys/src/cmd/postscript/tcpostio/mkfile create mode 100755 sys/src/cmd/postscript/tcpostio/tcpostio.c (limited to 'sys/src/cmd/postscript/tcpostio') diff --git a/sys/src/cmd/postscript/tcpostio/dial.c b/sys/src/cmd/postscript/tcpostio/dial.c new file mode 100755 index 000000000..da885d9b6 --- /dev/null +++ b/sys/src/cmd/postscript/tcpostio/dial.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DIALTIMEOUT 30 + +/* This is a dummy routine for non Plan9 systems. + * No attempt has been made to be clever, it's just + * supposed to work in this program. + */ +int dial_debug = 0; + +int +dial(char *dest, char *local, char *dir, int *cfdp) { + int sockconn, lport; + struct hostent *hp; /* Pointer to host info */ + struct sockaddr_in sin; /* Socket address, Internet style */ + struct servent *sp = 0; + char *tdest, *netname, *hostname, *servname; + int sock_type; +#ifndef plan9 +#define USED(x) if(x); else + int sockoption, sockoptsize; +#endif + + USED(dir); + USED(cfdp); + if ((tdest = malloc(strlen(dest)+1)) == NULL) { + if (dial_debug) fprintf(stderr, "dial: could not allocate memory\n"); + return(-1); + } + strcpy(tdest, dest); + + if ((netname = strtok(tdest, "!")) == NULL) { + fprintf(stderr, "dial: no network name\n"); + return(-1); + } + if (strcmp(netname, "tcp") == 0) { + sock_type = SOCK_STREAM; + } else if (strcmp(netname, "udp") == 0) { + sock_type = SOCK_DGRAM; + } else { + fprintf(stderr, "dial: network protocol name `%s' is invalid; must be `tcp' or `udp'\n", netname); + return(-1); + } + if ((hostname = strtok(0, "!")) == NULL) { + fprintf(stderr, "dial: no host name or number\n"); + return(-1); + } + if ((servname = strtok(0, "!")) == NULL) { + fprintf(stderr, "dial: no service name or number\n"); + return(-1); + } + hp = gethostbyname(hostname); + if (hp == (struct hostent *)NULL) { + if (dial_debug) fprintf(stderr, "host `%s' unknown by local host\n", hostname); + return(-1); + } + if (!isdigit(servname[0])) + sp = getservbyname(servname, netname); + sin.sin_addr.s_addr = *(unsigned long*)hp->h_addr; + sin.sin_port = htons((sp==0)?atoi(servname):sp->s_port); + sin.sin_family = AF_INET; + if (local == NULL) { + if ((sockconn = socket(AF_INET, sock_type, 0)) < 0) { + if (dial_debug) perror("dial:socket():"); + return(-1); + } + if (dial_debug) fprintf(stderr, "socket FD=%d\n", sockconn); + } else { + lport = atoi(local); + if ((lport < 512) || (lport >= 1024)) { + fprintf(stderr, "dial:invalid local port %d\n", lport); + return(-1); + } + if ((sockconn = rresvport(&lport)) < 0) { + if (dial_debug) perror("dial:rresvport():"); + return(-1); + } + } + if (dial_debug) { + fprintf(stderr, "sin size=%d\n", sizeof(sin)); + } + alarm(DIALTIMEOUT); + if ((connect(sockconn, (struct sockaddr *) &sin, sizeof(sin)) < 0)) { + if (dial_debug) perror("dial:connect():"); + return(-1); + } + alarm(0); +#ifndef plan9 + sockoptsize = sizeof(sockoption); + if (getsockopt(sockconn, SOL_SOCKET, SO_KEEPALIVE, &sockoption, &sockoptsize) < 0) { + if (dial_debug) perror("dial:getsockopt():"); + return(-1); + } + if (sockoptsize == sizeof(sockoption) && !sockoption) { + if (setsockopt(sockconn, SOL_SOCKET, SO_KEEPALIVE, &sockoption, sockoptsize) < 0) { + if (dial_debug) perror("dial:getsockopt():"); + return(-1); + } + } +#endif + return(sockconn); +} diff --git a/sys/src/cmd/postscript/tcpostio/mkfile b/sys/src/cmd/postscript/tcpostio/mkfile new file mode 100755 index 000000000..539f5907d --- /dev/null +++ b/sys/src/cmd/postscript/tcpostio/mkfile @@ -0,0 +1,16 @@ + syms diff --git a/sys/src/cmd/postscript/tcpostio/tcpostio.c b/sys/src/cmd/postscript/tcpostio/tcpostio.c new file mode 100755 index 000000000..4f0fdc007 --- /dev/null +++ b/sys/src/cmd/postscript/tcpostio/tcpostio.c @@ -0,0 +1,534 @@ +#include +#include + +#ifdef plan9 +#include +#endif + +#include +#include +#include +#include +#include + +#include + +extern int dial_debug; +extern int dial(char*, char*, char*, int*); + + +/* debug = 0 for no debugging */ +/* debug = 1 for readprinter debugging */ +/* debug = 2 for sendprinter debugging */ +/* debug = 3 for full debugging, its hard to read the messages */ + +int debug = 0; +#define READTIMEOUT 300 +#define RCVSELTIMEOUT 30 +#define SNDSELTIMEOUT 300 + +void +rdtmout(void) { + fprintf(stderr, "read timeout occurred, check printer\n"); +} + +int +getline(int fd, char *buf, int len) { + char *bp, c; + int i = 0, n; + + bp = buf; + while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) { + alarm(0); + if (*bp == '\r') continue; + i += n; + + c = *bp++; + if (c == '\n' || c == '\004' || i >= len-1) + break; + } + alarm(0); + if (n < 0) + return(n); + *bp = '\0'; + return(i); +} + +typedef struct { + char *state; /* printer's current status */ + int val; /* value returned by getstatus() */ +} Status; + +/* printer states */ +#define INITIALIZING 0 +#define IDLE 1 +#define BUSY 2 +#define WAITING 3 +#define PRINTING 4 +#define PRINTERERROR 5 +#define ERROR 6 +#define FLUSHING 7 +#define UNKNOWN 8 + +/* protocol requests and program states */ +#define START 'S' +unsigned char Start[] = { START }; +#define ID_LE 'L' +unsigned char Id_le[] = { ID_LE }; +#define REQ_STAT 'T' +unsigned char Req_stat[] = { REQ_STAT }; +#define SEND_DATA 'D' +unsigned char Send_data[] = { SEND_DATA }; +#define SENT_DATA 'A' +unsigned char Sent_data[] = { SENT_DATA }; +#define WAIT_FOR_EOJ 'W' +unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ }; +#define END_OF_JOB 'E' +unsigned char End_of_job[] = { END_OF_JOB }; +#define FATAL_ERROR 'F' +unsigned char Fatal_error[] = { FATAL_ERROR }; +#define WAIT_FOR_IDLE 'I' +unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE }; +#define OVER_AND_OUT 'O' +unsigned char Over_and_out[] = { OVER_AND_OUT }; + +Status statuslist[] = { + "initializing", INITIALIZING, + "idle", IDLE, + "busy", BUSY, + "waiting", WAITING, + "printing", PRINTING, + "printererror", PRINTERERROR, + "Error", ERROR, + "flushing", FLUSHING, + NULL, UNKNOWN +}; + + +/* find returns a pointer to the location of string str2 in string str1, + * if it exists. Otherwise, it points to the end of str1. + */ +char * +find(char *str1, char *str2) { + char *s1, *s2; + + for (; *str1!='\0'; str1++) { + for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ; + if ( *s2 == '\0' ) + break; + } + + return(str1); +} + +#define MESGSIZE 16384 +int blocksize = 1920; /* 19200/10, with 1 sec delay between transfers + * this keeps the queues from building up. + */ +char mesg[MESGSIZE]; /* exactly what came back on ttyi */ + +int +parsmesg(char *buf) { + static char sbuf[MESGSIZE]; + char *s; /* start of printer messsage in mesg[] */ + char *e; /* end of printer message in mesg[] */ + char *key, *val; /* keyword/value strings in sbuf[] */ + char *p; /* for converting to lower case etc. */ + int i; /* where *key was found in statuslist[] */ + + if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') { + strcpy(sbuf, s+3); /* don't change mesg[] */ + sbuf[e-(s+3)] = '\0'; /* ignore the trailing " ]%" */ + + for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :")) { + if (strcmp(key, "Error") == 0) + return(ERROR); + if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0) + key = val; + + for (; *key == ' '; key++) ; /* skip any leading spaces */ + for (p = key; *p; p++) /* convert to lower case */ + if (*p == ':') { + *p = '\0'; + break; + } else if (isupper(*p)) *p = tolower(*p); + + for (i=0; statuslist[i].state != NULL; i++) { + if (strcmp(statuslist[i].state, key) == 0) + return(statuslist[i].val); + } + } + } + return(UNKNOWN); +} + +char buf[MESGSIZE]; +fd_set readfds, writefds, exceptfds; +struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 }; +struct timeval sndtimeout = { SNDSELTIMEOUT, 0 }; + +int +readprinter(int printerfd, int pipefd) +{ + unsigned char proto; + int progstate = START; + int print_wait_msg = 0; + int tocount = 0; + int c, printstat, lastprintstat, n, nfds; + + + nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1; + printstat = 0; + signal(SIGALRM, rdtmout); + do { + +reselect: + /* ask sending process to request printer status */ + if (write(pipefd, Req_stat, 1) != 1) { + fprintf(stderr, "request status failed\n"); + progstate = FATAL_ERROR; + continue; + } + FD_ZERO(&readfds); /* lets be anal */ + FD_SET(printerfd, &readfds); + FD_SET(pipefd, &readfds); + FD_ZERO(&exceptfds); + FD_SET(printerfd, &exceptfds); + FD_SET(pipefd, &exceptfds); + n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout); + if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n); + if (n == 0) { + /* a timeout occurred */ + if (++tocount > 4) { + fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n"); + tocount = 0; + } + goto reselect; + } + if (n > 0 && FD_ISSET(printerfd, &exceptfds)) { + /* printer problem */ + fprintf(stderr, "printer exception\n"); + if (write(pipefd, Fatal_error, 1) != 1) { + fprintf(stderr, "'fatal error' write to pipe failed\n"); + } + progstate = FATAL_ERROR; + continue; + } + if (n > 0 && FD_ISSET(pipefd, &exceptfds)) { + /* pipe problem */ + fprintf(stderr, "pipe exception\n"); + progstate = FATAL_ERROR; + continue; + } + if (n > 0 && FD_ISSET(pipefd, &readfds)) { + /* protocol pipe wants to be read */ + if (debug&0x1) fprintf(stderr, "pipe wants to be read\n"); + if (read(pipefd, &proto, 1) != 1) { + fprintf(stderr, "read protocol pipe failed\n"); + progstate = FATAL_ERROR; + continue; + } + if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto); + /* change state? */ + switch (proto) { + case SENT_DATA: + break; + case WAIT_FOR_EOJ: + if (!print_wait_msg) { + print_wait_msg = 1; + fprintf(stderr, "waiting for end of job\n"); + } + progstate = proto; + break; + default: + fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto); + break; + } + n--; + } + if (n > 0 && FD_ISSET(printerfd, &readfds)) { + /* printer wants to be read */ + if (debug&0x1) fprintf(stderr, "printer wants to be read\n"); + if ((c=getline(printerfd, buf, MESGSIZE)) < 0) { + fprintf(stderr, "read printer failed\n"); + progstate = FATAL_ERROR; + continue; + } + if (debug&0x1) fprintf(stderr, "%s\n", buf); + if (c==1 && *buf == '\004') { + if (progstate == WAIT_FOR_EOJ) { + if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate); + fprintf(stderr, "%%[ status: endofjob ]%%\n"); +/* progstate = WAIT_FOR_IDLE; */ + progstate = OVER_AND_OUT; + if (write(pipefd, Over_and_out, 1) != 1) { + fprintf(stderr, "'fatal error' write to pipe failed\n"); + } + continue; + } else { + if (printstat == ERROR) { + progstate = FATAL_ERROR; + continue; + } + if (progstate != START && progstate != WAIT_FOR_IDLE) + fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate); + + } + continue; + } + + /* figure out if it was a status line */ + lastprintstat = printstat; + printstat = parsmesg(buf); + if (printstat == UNKNOWN || printstat == ERROR + || lastprintstat != printstat) { + /* print whatever it is that was read */ + fprintf(stderr, buf); + fflush(stderr); + if (printstat == UNKNOWN) { + printstat = lastprintstat; + continue; + } + } + switch (printstat) { + case UNKNOWN: + continue; /* shouldn't get here */ + case FLUSHING: + case ERROR: + progstate = FATAL_ERROR; + /* ask sending process to die */ + if (write(pipefd, Fatal_error, 1) != 1) { + fprintf(stderr, "Fatal_error mesg write to pipe failed\n"); + } + continue; + case INITIALIZING: + case PRINTERERROR: + sleep(1); + break; + case IDLE: + if (progstate == WAIT_FOR_IDLE) { + progstate = OVER_AND_OUT; + if (write(pipefd, Over_and_out, 1) != 1) { + fprintf(stderr, "'fatal error' write to pipe failed\n"); + } + continue; + } + progstate = SEND_DATA; + + goto dowait; + case BUSY: + case WAITING: + default: + sleep(1); +dowait: + switch (progstate) { + case WAIT_FOR_IDLE: + case WAIT_FOR_EOJ: + case START: + sleep(5); + break; + + case SEND_DATA: + if (write(pipefd, Send_data, 1) != 1) { + fprintf(stderr, "send data write to pipe failed\n"); + progstate = FATAL_ERROR; + continue; + } + break; + default: + fprintf(stderr, "unexpected program state %c\n", progstate); + exit(1); + } + break; + } + n--; + } + if (n > 0) { + fprintf(stderr, "more fds selected than requested!\n"); + exit(1); + }; + } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT)); + + if (progstate == FATAL_ERROR) + return(1); + else + return(0); +} + +int +sendfile(int infd, int printerfd, int pipefd) +{ + unsigned char proto; + int progstate = START; + int i, n, nfds; + int bytesread, bytesent = 0; + + nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1; + + if (write(printerfd, "\004", 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } + do { + FD_ZERO(&readfds); /* lets be anal */ + FD_SET(pipefd, &readfds); + n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout); + if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n); + if (n > 0 && FD_ISSET(pipefd, &readfds)) { + /* protocol pipe wants to be read */ + if (read(pipefd, &proto, 1) != 1) { + fprintf(stderr, "read protocol pipe failed\n"); + return(1); + } + /* change state? */ + if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto); + switch (proto) { + case OVER_AND_OUT: + case END_OF_JOB: + progstate = proto; + break; + case SEND_DATA: + bytesread = 0; + do { + i = read(infd, &buf[bytesread], blocksize-bytesread); + if (debug&02) fprintf(stderr, "read %d bytes\n", i); + if (i > 0) + bytesread += i; + } while((i > 0) && (bytesread < blocksize)); + if (i < 0) { + fprintf(stderr, "input file read error\n"); + progstate = FATAL_ERROR; + break; /* from switch */ + } + if (bytesread > 0) { + if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread); + if (write(printerfd, buf, bytesread)!=bytesread) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else if (write(pipefd, Sent_data, 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else { + bytesent += bytesread; + } + fprintf(stderr, "%d sent\n", bytesent); + fflush(stderr); + + /* we have reached the end of the input file */ + } + if (i == 0) { + if (progstate != WAIT_FOR_EOJ) { + if (write(printerfd, "\004", 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else if (write(pipefd, Wait_for_eoj, 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else { + progstate = WAIT_FOR_EOJ; + } + } + } + break; + case REQ_STAT: + if (write(printerfd, "\024", 1)!=1) { + fprintf(stderr, "write to printer failed\n"); + progstate = FATAL_ERROR; + } + if (debug&02) fprintf(stderr, "^T"); + break; + case FATAL_ERROR: + progstate = FATAL_ERROR; + } + } else if (n < 0) { + perror("sendfile:select:"); + progstate = FATAL_ERROR; + } else if (n == 0) { + sleep(1); + fprintf(stderr, "sendfile timeout\n"); + progstate = FATAL_ERROR; + } + } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT)); + if (write(printerfd, "\004", 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } + + if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent); + if (progstate == FATAL_ERROR) + return(1); + else + return(0); +} + +void main(int argc, char *argv[]) { + int c, usgflg=0, infd, printerfd; + int cpid; + int pipefd[2]; + char *dialstr; + unsigned long rprv, sprv; + + dialstr = 0; + + while ((c = getopt(argc, argv, "b:d:")) != -1) + switch (c) { + case 'b': + blocksize = atoi(optarg)/10; + if (blocksize > MESGSIZE || blocksize < 1) + blocksize = MESGSIZE; + break; + case 'd': + debug = atoi(optarg); + dial_debug = debug; + break; + case '?': + fprintf(stderr, "unknown option %c\n", c); + usgflg++; + } + if (optind < argc) + dialstr = argv[optind++]; + else { + usgflg++; + } + if (usgflg) { + fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n", argv[0]); + exit (2); + } + if (optind < argc) { + infd = open(argv[optind], 0); + if (infd < 0) { + fprintf(stderr, "cannot open %s\n", argv[optind]); + exit(1); + } + optind++; + } else + infd = 0; + + if (debug & 02) fprintf(stderr, "blocksize=%d\n", blocksize); + if (debug) fprintf(stderr, "dialing address=%s\n", dialstr); + printerfd = dial(dialstr, 0, 0, 0); + if (printerfd < 0) exit(1); + + fprintf(stderr, "printer startup\n"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) { + perror("socketpair"); + exit(1); + } + switch(cpid = fork()){ + case -1: + perror("fork error"); + exit(1); + case 0: + close(pipefd[1]); + sprv = sendfile(infd, printerfd, pipefd[0]); /* child - to printer */ + if (debug) fprintf(stderr, "to remote - exiting\n"); + exit(sprv); + default: + close(pipefd[0]); + rprv = readprinter(printerfd, pipefd[1]); /* parent - from printer */ + if (debug) fprintf(stderr, "from remote - exiting\n"); + while(wait(&sprv) != cpid); + exit(rprv|sprv); + } +} -- cgit v1.2.3