|
|
1.1 ! root 1: #include <stddef.h> ! 2: #include <stdio.h> ! 3: #include <signal.h> ! 4: #include <errno.h> ! 5: #include <time.h> ! 6: #include <stdarg.h> ! 7: ! 8: /* for Tenth Edition systems */ ! 9: #define LP "/usr/bin/lp" ! 10: /* for System V or BSD systems */ ! 11: /* #define LP "/v/bin/lp" */ ! 12: ! 13: #define LPDAEMONLOG "/tmp/lpdaemonl" ! 14: ! 15: #define ARGSIZ 4096 ! 16: #define NAMELEN 11 ! 17: ! 18: char argvstr[ARGSIZ]; /* arguments after parsing */ ! 19: char *argvals[ARGSIZ/2+1]; /* pointers to arguments after parsing */ ! 20: int ascnt = 0, argcnt = 0; /* number of arguments parsed */ ! 21: /* for 'stuff' gleened from lpr cntrl file */ ! 22: struct jobinfo { ! 23: char user[NAMELEN+1]; ! 24: char host[NAMELEN+1]; ! 25: } *getjobinfo(); ! 26: ! 27: #define MIN(a,b) ((a<b)?a:b) ! 28: ! 29: #define CPYFIELD(src, dst) { while (*(src)!=' ' && *(src)!='\t' && *(src)!='\r' && *(src)!='\n' && *(src)!='\0') *(dst)++ = *(src)++; } ! 30: ! 31: #define ACK() write(1, "", 1) ! 32: #define NAK() write(1, "\001", 1) ! 33: ! 34: #define LNBFSZ 4096 ! 35: char lnbuf[LNBFSZ]; ! 36: int readline(); ! 37: ! 38: #define RDSIZE 512 ! 39: char jobbuf[RDSIZE]; ! 40: ! 41: int datafd[400], cntrlfd; ! 42: ! 43: int dbgstate = 0; ! 44: char *dbgstrings[] = { ! 45: "", ! 46: "sendack1", ! 47: "send", ! 48: "rcvack", ! 49: "sendack2", ! 50: "done" ! 51: }; ! 52: ! 53: void ! 54: error(char *s1, ...) ! 55: { ! 56: FILE *fp; ! 57: long thetime; ! 58: char *chartime; ! 59: va_list ap; ! 60: char *args[8]; ! 61: int argno = 0; ! 62: ! 63: if((fp=fopen(LPDAEMONLOG, "a"))==NULL) ! 64: return; ! 65: ! 66: time(&thetime); ! 67: chartime = ctime(&thetime); ! 68: fprintf(fp, "%.15s ", &(chartime[4])); ! 69: va_start(ap, s1); ! 70: while((args[argno++] = va_arg(ap, char*)) && argno<8); ! 71: va_end(ap); ! 72: fprintf(fp, s1, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); ! 73: fclose(fp); ! 74: return; ! 75: } ! 76: ! 77: void ! 78: forklp(int inputfd) ! 79: { ! 80: int i, cpid; ! 81: char *bp, *cp; ! 82: char logent[LNBFSZ]; ! 83: ! 84: /* log this call to lp */ ! 85: cp = logent; ! 86: for (i=1; i<argcnt; i++) { ! 87: bp = argvals[i]; ! 88: if (cp+strlen(bp)+1 < logent+LNBFSZ-1) { ! 89: CPYFIELD(bp, cp); ! 90: *cp++ = ' '; ! 91: } ! 92: } ! 93: *--cp = '\n'; ! 94: *++cp = '\0'; ! 95: error(logent); ! 96: switch((cpid=fork())){ ! 97: case -1: ! 98: error("fork error\n"); ! 99: exit(2); ! 100: case 0: ! 101: if (inputfd != 0) ! 102: dup2(inputfd, 0); ! 103: dup2(1, 2); ! 104: lseek(0, 0L, 0); ! 105: execvp(LP, argvals); ! 106: error("exec failed\n"); ! 107: exit(3); ! 108: default: ! 109: while(wait((int *)0) != cpid); ! 110: } ! 111: } ! 112: ! 113: int ! 114: tempfile(void) ! 115: { ! 116: static tindx = 0; ! 117: char tmpf[20]; ! 118: int crtfd, tmpfd; ! 119: ! 120: sprintf(tmpf, "/tmp/lp%d.%d", getpid(), tindx++); ! 121: if((crtfd=creat(tmpf, 0666)) < 0) { ! 122: error("cannot create temp file %s\n", tmpf); ! 123: NAK(); ! 124: exit(3); ! 125: } ! 126: if((tmpfd=open(tmpf, 2)) < 0) { ! 127: error("cannot open temp file %s\n", tmpf); ! 128: NAK(); ! 129: exit(3); ! 130: } ! 131: close(crtfd); ! 132: unlink(tmpf); /* comment out for debugging */ ! 133: return(tmpfd); ! 134: } ! 135: ! 136: int ! 137: getfiles(void) ! 138: { ! 139: char *ap; ! 140: int filecnt, bsize, rv; ! 141: ! 142: filecnt = 0; ! 143: /* get a line, hopefully containing a ctrl char, size, and name */ ! 144: for(;;) { ! 145: ap = lnbuf; ! 146: do { ! 147: if ((rv = read(1, ap, 1)) != 1) { ! 148: if (rv < 0) { ! 149: error("Lost connection\n"); ! 150: NAK(); ! 151: } ! 152: return(filecnt); ! 153: } ! 154: } while (*ap != '\n' && (ap++ - lnbuf < LNBFSZ - 1)); ! 155: *ap = '\0'; ! 156: ap = lnbuf; ! 157: switch(*ap++) { ! 158: case '\1': /* cleanup - data sent was bad (whatever that means) */ ! 159: break; ! 160: case '\2': /* read control file */ ! 161: bsize = atoi(ap); ! 162: cntrlfd = tempfile(); ! 163: if (readfile(cntrlfd, bsize) < 0) { ! 164: close(cntrlfd); ! 165: NAK(); ! 166: return(0); ! 167: } ! 168: return(filecnt); ! 169: case '\3': /* read data file */ ! 170: bsize = atoi(ap); ! 171: datafd[filecnt] = tempfile(); ! 172: readfile(datafd[filecnt++], bsize); ! 173: break; ! 174: default: ! 175: error("protocol error <%d>\n", *(ap-1)); ! 176: NAK(); ! 177: } ! 178: } ! 179: } ! 180: ! 181: int ! 182: readfile(int outfd, int bsize) ! 183: { ! 184: int rv; ! 185: ! 186: dbgstate = 1; ! 187: alarm(60); ! 188: ACK(); ! 189: dbgstate = 2; ! 190: for(; bsize > 0; bsize -= rv) { ! 191: alarm(60); ! 192: if((rv=read(0, jobbuf, MIN(bsize,RDSIZE))) < 0) { ! 193: error("error reading input, %d unread\n", bsize); ! 194: exit(4); ! 195: } else if((write(outfd, jobbuf, rv)) != rv) { ! 196: error("error writing temp file, %d unread\n", bsize); ! 197: exit(5); ! 198: } ! 199: } ! 200: dbgstate = 3; ! 201: alarm(60); ! 202: if (((rv=read(0, jobbuf, 1))==1) && (*jobbuf=='\0')) { ! 203: alarm(60); ! 204: ACK(); ! 205: dbgstate = 4; ! 206: alarm(0); ! 207: return(outfd); ! 208: } ! 209: alarm(0); ! 210: error("received bad status <%d> from sender\n", *jobbuf); ! 211: error("rv=%d\n", rv); ! 212: NAK(); ! 213: return(-1); ! 214: } ! 215: ! 216: struct jobinfo * ! 217: getjobinfo(int fd) ! 218: { ! 219: register char *ap; ! 220: int rv; ! 221: static struct jobinfo info; ! 222: ! 223: if (lseek(fd, 0L, 0) < 0) { ! 224: error("error seeking in temp file\n"); ! 225: exit(7); ! 226: } ! 227: /* the following strings should be < NAMELEN or else they will not ! 228: * be null terminated. ! 229: */ ! 230: strncpy(info.user, "daemon", NAMELEN); ! 231: strncpy(info.host, "nowhere", NAMELEN); ! 232: /* there may be a space after the name and host. It will be filtered out ! 233: * by CPYFIELD. ! 234: */ ! 235: while ((rv=readline(fd)) != 0) { ! 236: ap = lnbuf; ! 237: ap[rv-1] = '\0'; /* remove newline from string */ ! 238: switch (*ap) { ! 239: case 'H': ! 240: strncpy(info.host, &ap[1], NAMELEN); ! 241: break; ! 242: case 'P': ! 243: strncpy(info.user, &ap[1], NAMELEN); ! 244: break; ! 245: } ! 246: } ! 247: return(&info); ! 248: } ! 249: ! 250: int ! 251: readline(int inpfd) ! 252: { ! 253: register char *ap; ! 254: register int i; ! 255: ! 256: ap = lnbuf; ! 257: i = 0; ! 258: do { ! 259: if (read(inpfd, ap, 1) != 1) { ! 260: error("read error\n"); ! 261: break; ! 262: } ! 263: i++; ! 264: } while (*ap++ != '\n' && (i < LNBFSZ - 2)); ! 265: if (*(ap-1) != '\n') { ! 266: *(ap-1) = '\n'; ! 267: i++; ! 268: } ! 269: *ap = '\0'; ! 270: return(i); ! 271: } ! 272: ! 273: void ! 274: alarmhandler(int sig) { ! 275: signal(sig, alarmhandler); ! 276: error("alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); ! 277: } ! 278: ! 279: main() ! 280: { ! 281: char *ap, *bp, *cp, *savbufpnt; ! 282: int i, rv, saveflg, savargcnt; ! 283: struct jobinfo *jinfop; ! 284: ! 285: signal(1, SIG_IGN); /* SIGHUP not in lcc */ ! 286: signal(14, alarmhandler); /* SIGALRM not in lcc */ ! 287: cp = argvstr; ! 288: /* setup argv[0] for exec */ ! 289: argvals[argcnt++] = cp; ! 290: for (bp = LP, i = 0; (*bp != '\0') && (i < ARGSIZ-1); *cp++ = *bp++, i++); ! 291: *cp++ = '\0'; ! 292: /* get the first line sent and parse it as arguments for lp */ ! 293: ap = lnbuf; ! 294: i = 0; ! 295: do { ! 296: if ((rv = read(0, ap, 1)) != 1) { ! 297: if (rv < 0) { ! 298: error("Lost connection\n"); ! 299: } ! 300: exit(1); ! 301: } ! 302: i++; ! 303: } while (*ap++ != '\n' && (i < LNBFSZ - 2)); ! 304: if (*(ap-1) != '\n') { ! 305: *(ap-1) = '\n'; ! 306: i++; ! 307: } ! 308: *ap = '\0'; ! 309: ap = lnbuf; ! 310: if (ap == (char *)0) { ! 311: error("cannot read arg line\n"); ! 312: NAK(); ! 313: exit(1); ! 314: } ! 315: bp = ap; ! 316: /* setup the remaining arguments */ ! 317: /* check for BSD style request */ ! 318: /* ^A, ^B, ^C, ^D, ^E (for BSD lpr) */ ! 319: switch (*bp) { ! 320: case '\001': ! 321: case '\003': ! 322: case '\004': ! 323: bp++; /* drop the ctrl character from the input */ ! 324: argvals[argcnt++] = cp; ! 325: *cp++ = '-'; *cp++ = 'q'; *cp++ = '\0'; /* -q */ ! 326: argvals[argcnt++] = cp; ! 327: *cp++ = '-'; *cp++ = 'd'; /* -d */ ! 328: CPYFIELD(bp, cp); /* printer */ ! 329: *cp++ = '\0'; ! 330: break; ! 331: case '\002': ! 332: bp++; /* drop the ctrl character from the input */ ! 333: argvals[argcnt++] = cp; ! 334: *cp++ = '-'; *cp++ = 'd'; /* -d */ ! 335: CPYFIELD(bp, cp); /* printer */ ! 336: *cp++ = '\0'; ! 337: ACK(); ! 338: savargcnt = argcnt; ! 339: savbufpnt = cp; ! 340: while ((rv=getfiles())) { ! 341: jinfop = getjobinfo(cntrlfd); ! 342: close(cntrlfd); ! 343: argcnt = savargcnt; ! 344: cp = savbufpnt; ! 345: argvals[argcnt++] = cp; ! 346: *cp++ = '-'; *cp++ = 'M'; /* -M */ ! 347: bp = jinfop->host; ! 348: CPYFIELD(bp, cp); /* host name */ ! 349: *cp++ = '\0'; ! 350: argvals[argcnt++] = cp; ! 351: *cp++ = '-'; *cp++ = 'u'; /* -u */ ! 352: bp = jinfop->user; ! 353: CPYFIELD(bp, cp); /* user name */ ! 354: *cp++ = '\0'; ! 355: for(i=0;i<rv;i++) ! 356: forklp(datafd[i]); ! 357: } ! 358: exit(0); ! 359: case '\005': ! 360: bp++; /* drop the ctrl character from the input */ ! 361: argvals[argcnt++] = cp; ! 362: *cp++ = '-'; *cp++ = 'k'; *cp++ = '\0'; /* -k */ ! 363: argvals[argcnt++] = cp; ! 364: *cp++ = '-'; *cp++ = 'd'; /* -d */ ! 365: CPYFIELD(bp, cp); /* printer */ ! 366: *cp++ = '\0'; ! 367: argvals[argcnt++] = cp; ! 368: *cp++ = '-'; *cp++ = 'u'; /* -u */ ! 369: CPYFIELD(bp, cp); /* username */ ! 370: *cp++ = '\0'; ! 371: datafd[0] = tempfile(); ! 372: fprint(datafd[0], "%s\n", bp); ! 373: break; ! 374: default: ! 375: /* otherwise get my lp arguments */ ! 376: do { ! 377: /* move to next non-white space */ ! 378: while (*bp==' '||*bp=='\t') ! 379: ++bp; ! 380: if (*bp=='\n') continue; ! 381: /* only accept arguments beginning with - ! 382: * this is done to prevent the printing of ! 383: * local files from the destination host ! 384: */ ! 385: if (*bp=='-') { ! 386: argvals[argcnt++] = cp; ! 387: saveflg = 1; ! 388: } else ! 389: saveflg = 0; ! 390: /* move to next white space copying text to argument buffer */ ! 391: while (*bp!=' ' && *bp!='\t' && *bp!='\n' ! 392: && *bp!='\0') { ! 393: *cp = *bp++; ! 394: cp += saveflg; ! 395: } ! 396: *cp = '\0'; ! 397: cp += saveflg; ! 398: } while (*bp!='\n'); ! 399: readline(0); ! 400: datafd[0] = tempfile(); ! 401: if(readfile(datafd[0], atoi(lnbuf)) < 0) { ! 402: error("readfile failed\n"); ! 403: exit(7); ! 404: } ! 405: } ! 406: forklp(datafd[0]); ! 407: exit(0); ! 408: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.