|
|
researchv10 Norman
#include <stddef.h>
#include <stdarg.h>
#include <signal.h>
#include <fio.h>
#include <errno.h>
#include <time.h>
/* for Tenth Edition systems */
#define LP "/usr/bin/lp"
/* for System V or BSD systems */
/* #define LP "/v/bin/lp" */
#define LPDAEMONLOG "/tmp/lpdaemonl"
#define ARGSIZ 4096
#define NAMELEN 11
char argvstr[ARGSIZ]; /* arguments after parsing */
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
char lnbuf[LNBFSZ];
int readline();
#define RDSIZE 512
char jobbuf[RDSIZE];
int datafd[400], cntrlfd;
void
error(int level, char *s1, ...)
{
int fd;
long thetime;
char *chartime;
va_list ap;
char *args[8];
int argno = 0;
if((fd=open(LPDAEMONLOG, 1))<0) {
if(errno==ENOENT) {
if((fd=creat(LPDAEMONLOG, 0664))<0) {
return; /* hopeless, just go away mad */
}
} else return;
}
lseek(fd, 0, 2);
if (level == 0) {
time(&thetime);
chartime = ctime(&thetime);
fprint(fd, "%.15s ", &(chartime[4]));
}
va_start(ap, s1);
while(args[argno++] = va_arg(ap, char*));
va_end(ap);
fprint(fd, s1, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
close(fd);
return;
}
void
forklp(int inputfd)
{
int i, cpid;
char *bp, *cp;
char logent[LNBFSZ];
/* log this call to lp */
cp = logent;
for (i=1; i<argcnt; i++) {
bp = argvals[i];
if (cp+strlen(bp)+1 < logent+LNBFSZ-1) {
CPYFIELD(bp, cp);
*cp++ = ' ';
}
}
*--cp = '\n';
*++cp = '\0';
error(0, logent);
switch((cpid=fork())){
case -1:
error(0, "fork error\n");
exit(2);
case 0:
if (inputfd != 0)
dup2(inputfd, 0);
dup2(1, 2);
lseek(0, 0L, 0);
execvp(LP, argvals);
error(0, "exec failed\n");
exit(3);
default:
while(wait((int *)0) != cpid);
}
}
int
getfiles(void)
{
char *ap;
int filecnt, bsize, rv;
filecnt = 0;
/* get a line, hopefully containing a ctrl char, size, and name */
for(;;) {
ap = lnbuf;
do {
if ((rv = read(1, ap, 1)) != 1) {
if (rv < 0) {
error(0, "Lost connection\n");
NAK();
}
return(filecnt);
}
} while (*ap != '\n' && (ap++ - lnbuf < LNBFSZ - 1));
*ap = '\0';
ap = lnbuf;
switch(*ap++) {
case '\1': /* cleanup - data sent was bad (whatever that means) */
break;
case '\2': /* read control file */
bsize = atoi(ap);
cntrlfd = tmpfile();
if (readfile(cntrlfd, bsize) < 0) {
close(cntrlfd);
NAK();
return(0);
}
return(filecnt);
case '\3': /* read data file */
bsize = atoi(ap);
datafd[filecnt] = tmpfile();
readfile(datafd[filecnt++], bsize);
break;
default:
error(0, "protocol error <%d>\n", *(ap-1));
NAK();
}
}
}
int
readfile(int outfd, int bsize)
{
int bcnt, rv;
ACK();
for(bcnt=bsize ; bcnt > 0; bcnt -= rv) {
if((rv=read(0, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
error(0, "error reading input\n");
exit(4);
} else if((write(outfd, jobbuf, rv)) != rv) {
error(0, "error writing temp file\n");
exit(5);
}
}
if (((rv=read(0, jobbuf, 1))==1) && (*jobbuf=='\0')) {
ACK();
return(outfd);
}
error(0, "received bad status <%d> from sender ", *jobbuf);
error(1, "rv=%d\n", rv);
NAK();
return(-1);
}
struct jobinfo *
getjobinfo(int fd)
{
register char *ap;
int rv;
static struct jobinfo info;
if (lseek(fd, 0L, 0) < 0) {
error(0, "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':
strncpy(info.host, &ap[1], NAMELEN);
break;
case 'P':
strncpy(info.user, &ap[1], NAMELEN);
break;
}
}
return(&info);
}
int
tmpfile(void)
{
static tindx = 0;
char tmpf[20];
int crtfd, tmpfd;
sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
if((crtfd=creat(tmpf, 0666)) < 0) {
error(0, "cannot create temp file %s\n", tmpf);
NAK();
exit(3);
}
if((tmpfd=open(tmpf, 2)) < 0) {
error(0, "cannot open temp file %s\n", tmpf);
NAK();
exit(3);
}
close(crtfd);
/* unlink(tmpf); /* comment out for debugging */
return(tmpfd);
}
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\n");
break;
}
i++;
} while (*ap++ != '\n' && (i < LNBFSZ - 2));
if (*(ap-1) != '\n') {
*(ap-1) = '\n';
i++;
}
*ap = '\0';
return(i);
}
main()
{
char *ap, *bp, *cp, *savbufpnt;
int i, rv, saveflg, savargcnt;
struct jobinfo *jinfop;
signal(1, SIG_IGN);
cp = argvstr;
/* setup argv[0] for exec */
argvals[argcnt++] = cp;
for (bp = 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 */
ap = lnbuf;
i = 0;
do {
if ((rv = read(0, ap, 1)) != 1) {
if (rv < 0) {
error(0, "Lost connection\n");
}
exit(1);
}
i++;
} while (*ap++ != '\n' && (i < LNBFSZ - 2));
if (*(ap-1) != '\n') {
*(ap-1) = '\n';
i++;
}
*ap = '\0';
ap = lnbuf;
if (ap == (char *)0) {
error(0, "cannot read arg line\n");
NAK();
exit(1);
}
bp = ap;
/* 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 = jinfop->host;
CPYFIELD(bp, cp); /* host name */
*cp++ = '\0';
argvals[argcnt++] = cp;
*cp++ = '-'; *cp++ = 'u'; /* -u */
bp = 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++ = '-'; *cp++ = 'u'; /* -u */
CPYFIELD(bp, cp); /* username */
*cp++ = '\0';
datafd[0] = tmpfile();
fprint(datafd[0], "%s\n", bp);
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');
readline(0);
datafd[0] = tmpfile();
error(0, "reading in %d bytes <%s>\n", atoi(lnbuf), lnbuf);
if(readfile(datafd[0], atoi(lnbuf)) < 0) {
error(0, "readfile failed\n");
exit(7);
}
}
forklp(datafd[0]);
exit(0);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.