321 lines
5.9 KiB
C
321 lines
5.9 KiB
C
#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
|
|
}
|