1: /* 2: * Copyright (c) 1986 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: */ 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)db_dump.c 4.20 (Berkeley) 2/17/88"; 15: #endif /* not lint */ 16: 17: #include <sys/param.h> 18: #include <sys/time.h> 19: #include <sys/stat.h> 20: #include <netinet/in.h> 21: #include <netdb.h> 22: #include <stdio.h> 23: #include <syslog.h> 24: #include <arpa/nameser.h> 25: #include "ns.h" 26: #include "db.h" 27: 28: extern char *p_type(), *p_class(); 29: 30: #ifdef DUMPFILE 31: char *dumpfile = DUMPFILE; 32: #else 33: char *dumpfile = "/usr/tmp/named_dump.db"; 34: #endif 35: 36: extern char *cache_file; 37: 38: /* 39: * Dump current cache in a format similar to RFC 883. 40: * 41: * We try to be careful and determine whether the operation succeeded 42: * so that the new cache file can be installed. 43: */ 44: 45: #define DB_ROOT_TIMBUF 3600 46: 47: doachkpt() 48: { 49: extern int errno; 50: FILE *fp; 51: char tmpcheckfile[256]; 52: 53: /* nowhere to checkpoint cache... */ 54: if (cache_file == NULL) { 55: #ifdef DEBUG 56: if (debug >= 3) 57: fprintf(ddt,"doachkpt(to where?)\n"); 58: #endif 59: return; 60: } 61: 62: #ifdef DEBUG 63: if (debug >= 3) 64: fprintf(ddt,"doachkpt()\n"); 65: #endif 66: 67: (void) sprintf(tmpcheckfile, "%s.chk", cache_file); 68: if ((fp = fopen(tmpcheckfile, "w")) == NULL) { 69: #ifdef DEBUG 70: if (debug >= 3) 71: fprintf(ddt,"doachkpt(can't open %s for write)\n", tmpcheckfile); 72: #endif 73: return; 74: } 75: 76: (void) gettime(&tt); 77: fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); 78: fflush(fp); 79: if (ferror(fp)) { 80: #ifdef DEBUG 81: if (debug >= 3) 82: fprintf(ddt,"doachkpt(write to checkpoint file failed)\n"); 83: #endif 84: return; 85: } 86: 87: if (fcachetab != NULL) { 88: int n; 89: if ((n = scan_root(hashtab)) < MINROOTS) { 90: syslog(LOG_ERR, "%d root hints... (too low)", n); 91: fprintf(fp, "; ---- Root hint cache dump ----\n"); 92: (void) db_dump(fcachetab, fp, DB_Z_CACHE, ""); 93: } 94: } 95: 96: if (hashtab != NULL) { 97: fprintf(fp, "; ---- Cache dump ----\n"); 98: if (db_dump(hashtab, fp, DB_Z_CACHE, "") == NODBFILE) { 99: #ifdef DEBUG 100: if (debug >= 3) 101: fprintf(ddt,"doachkpt(checkpoint failed)\n"); 102: #endif 103: (void) fclose(fp); 104: return; 105: } 106: } 107: 108: (void) fsync(fileno(fp)); 109: if (fclose(fp) == EOF) { 110: #ifdef DEBUG 111: if (debug >= 3) 112: fprintf(ddt,"doachkpt(close failed)\n"); 113: #endif 114: return; 115: } 116: 117: if (rename(tmpcheckfile, cache_file)) { 118: #ifdef DEBUG 119: if (debug >= 3) 120: fprintf(ddt,"doachkpt(install %s to %s failed, %d)\n", 121: tmpcheckfile,cache_file, errno); 122: #endif 123: } 124: } 125: 126: /* 127: * What we do is scan the root hint cache to make sure there are at least 128: * MINROOTS root pointers with non-0 TTL's so that the checkpoint will not 129: * lose the root. Failing this, all pointers are written out w/ TTL ~0 130: * (root pointers timed out and prime_cache() not done or failed). 131: */ 132: #define TIMBUF 300 133: 134: int 135: scan_root(htp) 136: struct hashbuf *htp; 137: { 138: register struct databuf *dp; 139: register struct namebuf *np; 140: struct timeval soon; 141: int roots = 0; 142: 143: #ifdef DEBUG 144: if (debug) 145: fprintf(ddt,"scan_root(0x%x)\n", htp); 146: #endif 147: 148: /* metric by which we determine whether a root NS pointer is still */ 149: /* valid (will be written out if we do a dump). we also add some */ 150: /* time buffer for safety... */ 151: (void) gettime(&soon); 152: soon.tv_sec += TIMBUF; 153: 154: for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { 155: if (np->n_dname[0] == '\0') { 156: dp = np->n_data; 157: while (dp != NULL) { 158: if (dp->d_type == T_NS && 159: dp->d_ttl > soon.tv_sec) { 160: roots++; 161: if (roots >= MINROOTS) 162: return (roots); 163: } 164: dp = dp->d_next; 165: } 166: } 167: } 168: return (roots); 169: } 170: 171: #ifdef notdef 172: mark_cache(htp, ttl) 173: struct hashbuf *htp; 174: u_long ttl; 175: { 176: register struct databuf *dp; 177: register struct namebuf *np; 178: struct namebuf **npp, **nppend; 179: struct timeval soon; 180: 181: #ifdef DEBUG 182: if (debug) 183: fprintf(ddt,"mark_cache()\n"); 184: #endif 185: 186: (void) gettime(&soon); 187: soon.tv_sec += TIMBUF; 188: 189: npp = htp->h_tab; 190: nppend = npp + htp->h_size; 191: while (npp < nppend) { 192: for (np = *npp++; np != NULL; np = np->n_next) { 193: if (np->n_data == NULL) 194: continue; 195: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { 196: if (dp->d_ttl < soon.tv_sec) 197: dp->d_ttl = ttl; 198: } 199: } 200: } 201: 202: npp = htp->h_tab; 203: nppend = npp + htp->h_size; 204: while (npp < nppend) { 205: for (np = *npp++; np != NULL; np = np->n_next) { 206: if (np->n_hash == NULL) 207: continue; 208: mark_cache(np->n_hash, ttl); 209: } 210: } 211: } 212: #endif notdef 213: 214: /* 215: * Dump current data base in a format similar to RFC 883. 216: */ 217: 218: doadump() 219: { 220: FILE *fp; 221: 222: #ifdef DEBUG 223: if (debug >= 3) 224: fprintf(ddt,"doadump()\n"); 225: #endif 226: 227: if ((fp = fopen(dumpfile, "w")) == NULL) 228: return; 229: gettime(&tt); 230: fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec)); 231: fprintf(fp, "; --- Cache & Data ---\n"); 232: if (hashtab != NULL) 233: (void) db_dump(hashtab, fp, DB_Z_ALL, ""); 234: fprintf(fp, "; --- Hints ---\n"); 235: if (fcachetab != NULL) 236: (void) db_dump(fcachetab, fp, DB_Z_ALL, ""); 237: (void) fclose(fp); 238: } 239: 240: /* Create a disk database to back up zones 241: */ 242: zonedump(zp) 243: register struct zoneinfo *zp; 244: { 245: FILE *fp; 246: char *fname; 247: struct hashbuf *htp; 248: char *op; 249: struct stat st; 250: 251: /* Only dump zone if there is a cache specified */ 252: if (zp->z_source && *(zp->z_source)) { 253: #ifdef DEBUG 254: if (debug) 255: fprintf(ddt, "zonedump(%s)\n", zp->z_source); 256: #endif 257: 258: if ((fp = fopen(zp->z_source, "w")) == NULL) 259: return; 260: if (op = index(zp->z_origin, '.')) 261: op++; 262: gettime(&tt); 263: htp = hashtab; 264: if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) { 265: db_dump(htp, fp, zp-zones, (op == NULL ? "" : op)); 266: #ifdef ALLOW_UPDATES 267: zp->hasChanged = 0; /* Checkpointed */ 268: #endif ALLOW_UPDATES 269: } 270: (void) fclose(fp); 271: if (stat(zp->z_source, &st) == 0) 272: zp->z_ftime = st.st_mtime; 273: } 274: #ifdef DEBUG 275: else if (debug) 276: fprintf(ddt, "zonedump: no zone to dump\n"); 277: #endif 278: } 279: 280: int 281: db_dump(htp, fp, zone, origin) 282: int zone; 283: struct hashbuf *htp; 284: FILE *fp; 285: char *origin; 286: { 287: register struct databuf *dp; 288: register struct namebuf *np; 289: struct namebuf **npp, **nppend; 290: char dname[MAXDNAME]; 291: u_long n; 292: u_long addr; 293: u_short i; 294: int j; 295: register u_char *cp; 296: char *proto; 297: extern char *inet_ntoa(), *p_protocal(), *p_service(); 298: int found_data, tab, printed_origin = 0; 299: 300: npp = htp->h_tab; 301: nppend = npp + htp->h_size; 302: while (npp < nppend) { 303: for (np = *npp++; np != NULL; np = np->n_next) { 304: if (np->n_data == NULL) 305: continue; 306: /* Blecch - can't tell if there is data here for the 307: * right zone, so can't print name yet 308: */ 309: found_data = 0; 310: /* we want a snapshot in time... */ 311: for (dp = np->n_data; dp != NULL; dp = dp->d_next) { 312: /* Is the data for this zone? */ 313: if (zone != DB_Z_ALL && dp->d_zone != zone) 314: continue; 315: if (dp->d_zone == DB_Z_CACHE && 316: dp->d_ttl <= tt.tv_sec && 317: (dp->d_flags & DB_F_HINT) == 0) 318: continue; 319: if (!printed_origin) { 320: fprintf(fp, "$ORIGIN %s.\n", origin); 321: printed_origin++; 322: } 323: tab = 0; 324: if (!found_data) { 325: if (np->n_dname[0] == 0) { 326: if (origin[0] == 0) 327: fprintf(fp, ".\t"); 328: else 329: fprintf(fp, ".%s.\t", origin); /* ??? */ 330: } else 331: fprintf(fp, "%s\t", np->n_dname); 332: if (strlen(np->n_dname) < 8) 333: tab = 1; 334: found_data++; 335: } else { 336: (void) putc('\t', fp); 337: tab = 1; 338: } 339: if (dp->d_zone == DB_Z_CACHE) { 340: if (dp->d_flags & DB_F_HINT && 341: (long)(dp->d_ttl - tt.tv_sec) < DB_ROOT_TIMBUF) 342: fprintf(fp, "%d\t", DB_ROOT_TIMBUF); 343: else 344: fprintf(fp, "%ld\t", 345: (dp->d_ttl - tt.tv_sec)); 346: } else if (dp->d_ttl != 0 && 347: dp->d_ttl != zones[dp->d_zone].z_minimum) 348: fprintf(fp, "%ld\t", dp->d_ttl); 349: else if (tab) 350: (void) putc('\t', fp); 351: fprintf(fp, "%s\t%s\t", p_class(dp->d_class), 352: p_type(dp->d_type)); 353: cp = (u_char *)dp->d_data; 354: /* 355: * Print type specific data 356: */ 357: switch (dp->d_type) { 358: case T_A: 359: switch (dp->d_class) { 360: case C_IN: 361: GETLONG(n, cp); 362: n = htonl(n); 363: fprintf(fp, "%s", 364: inet_ntoa(*(struct in_addr *)&n)); 365: break; 366: } 367: if (dp->d_nstime) 368: fprintf(fp, "\t; %ld", dp->d_nstime); 369: fprintf(fp, "\n"); 370: break; 371: case T_CNAME: 372: case T_MB: 373: case T_MG: 374: case T_MR: 375: case T_PTR: 376: if (cp[0] == '\0') 377: fprintf(fp, ".\n"); 378: else 379: fprintf(fp, "%s.\n", cp); 380: break; 381: 382: case T_NS: 383: cp = (u_char *)dp->d_data; 384: if (cp[0] == '\0') 385: fprintf(fp, ".\t"); 386: else 387: fprintf(fp, "%s.", cp); 388: if (dp->d_nstime) 389: fprintf(fp, "\t; %ld???", dp->d_nstime); 390: fprintf(fp, "\n"); 391: break; 392: 393: case T_HINFO: 394: if (n = *cp++) { 395: fprintf(fp, "\"%.*s\"", (int)n, cp); 396: cp += n; 397: } else 398: fprintf(fp, "\"\""); 399: if (n = *cp++) 400: fprintf(fp, " \"%.*s\"", (int)n, cp); 401: else 402: fprintf(fp, "\"\""); 403: (void) putc('\n', fp); 404: break; 405: 406: case T_SOA: 407: fprintf(fp, "%s.", cp); 408: cp += strlen(cp) + 1; 409: fprintf(fp, " %s. (\n", cp); 410: cp += strlen(cp) + 1; 411: GETLONG(n, cp); 412: fprintf(fp, "\t\t%lu", n); 413: GETLONG(n, cp); 414: fprintf(fp, " %lu", n); 415: GETLONG(n, cp); 416: fprintf(fp, " %lu", n); 417: GETLONG(n, cp); 418: fprintf(fp, " %lu", n); 419: GETLONG(n, cp); 420: fprintf(fp, " %lu )\n", n); 421: break; 422: 423: case T_MX: 424: GETSHORT(n, cp); 425: fprintf(fp,"%lu", n); 426: fprintf(fp," %s.\n", cp); 427: break; 428: 429: 430: case T_UINFO: 431: fprintf(fp, "\"%s\"\n", cp); 432: break; 433: 434: case T_UID: 435: case T_GID: 436: if (dp->d_size == sizeof(u_long)) { 437: GETLONG(n, cp); 438: fprintf(fp, "%lu\n", n); 439: } 440: break; 441: 442: case T_WKS: 443: GETLONG(addr, cp); 444: addr = htonl(addr); 445: fprintf(fp,"%s ", 446: inet_ntoa(*(struct in_addr *)&addr)); 447: proto = p_protocal(*cp); /* protocal */ 448: cp += sizeof(char); 449: fprintf(fp, "%s ", proto); 450: i = 0; 451: while(cp < (u_char *)dp->d_data + dp->d_size) { 452: j = *cp++; 453: do { 454: if(j & 0200) 455: fprintf(fp," %s", 456: p_service(i, proto)); 457: j <<= 1; 458: } while(++i & 07); 459: } 460: fprintf(fp,"\n"); 461: break; 462: 463: case T_MINFO: 464: fprintf(fp, "%s.", cp); 465: cp += strlen(cp) + 1; 466: fprintf(fp, " %s.\n", cp); 467: break; 468: #ifdef ALLOW_T_UNSPEC 469: case T_UNSPEC: 470: /* Dump binary data out in an ASCII-encoded 471: format */ 472: { 473: /* Allocate more than enough space: 474: * actually need 5/4 size + 20 or so 475: */ 476: int TmpSize = 2 * dp->d_size + 30; 477: char *TmpBuf = (char *) malloc(TmpSize); 478: if (TmpBuf == NULL) { 479: #ifdef DEBUG 480: if (debug) 481: fprintf(ddt, "Dump T_UNSPEC: malloc returned NULL\n"); 482: #endif DEBUG 483: syslog(LOG_ERR, "Dump T_UNSPEC: malloc: %m"); 484: } 485: if (btoa(cp, dp->d_size, TmpBuf, 486: TmpSize) == CONV_OVERFLOW) { 487: #ifdef DEBUG 488: if (debug) 489: fprintf(ddt, "Dump T_UNSPEC: Output buffer overflow\n"); 490: #endif DEBUG 491: syslog(LOG_ERR, "Dump T_UNSPEC: Output buffer overflow\n"); 492: } else 493: fprintf(fp, "%s\n", TmpBuf); 494: } 495: break; 496: #endif ALLOW_T_UNSPEC 497: default: 498: fprintf(fp, "???\n"); 499: } 500: } 501: } 502: } 503: if (ferror(fp)) 504: return(NODBFILE); 505: 506: npp = htp->h_tab; 507: nppend = npp + htp->h_size; 508: while (npp < nppend) { 509: for (np = *npp++; np != NULL; np = np->n_next) { 510: if (np->n_hash == NULL) 511: continue; 512: getname(np, dname, sizeof(dname)); 513: if (db_dump(np->n_hash, fp, zone, dname) == NODBFILE) 514: return(NODBFILE); 515: } 516: } 517: return(OK); 518: } 519: 520: /* These next two routines will be moveing to res_debug.c */ 521: /* They are currently here for ease of distributing the WKS record fix */ 522: char * 523: p_protocal(num) 524: int num; 525: { 526: static char number[8]; 527: struct protoent *pp; 528: extern struct protoent *cgetprotobynumber(); 529: 530: pp = cgetprotobynumber(num); 531: if(pp == 0) { 532: (void) sprintf(number, "%d", num); 533: return(number); 534: } 535: return(pp->p_name); 536: } 537: 538: char * 539: p_service(port, proto) 540: u_short port; 541: char *proto; 542: { 543: static char number[8]; 544: struct servent *ss; 545: extern struct servent *cgetservbyport(); 546: 547: ss = cgetservbyport(htons(port), proto); 548: if(ss == 0) { 549: (void) sprintf(number, "%d", port); 550: return(number); 551: } 552: return(ss->s_name); 553: } 554: 555: #ifdef ALLOW_T_UNSPEC 556: /* 557: * Subroutines to convert between 8 bit binary bytes and printable ASCII. 558: * Computes the number of bytes, and three kinds of simple checksums. 559: * Incoming bytes are collected into 32-bit words, then printed in base 85: 560: * exp(85,5) > exp(2,32) 561: * The ASCII characters used are between '!' and 'u'; 562: * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data. 563: * 564: * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for 565: * the atob/btoa programs, released with the compress program, in mod.sources. 566: * Modified by Mike Schwartz 8/19/86 for use in BIND. 567: */ 568: 569: /* Make sure global variable names are unique */ 570: #define Ceor T_UNSPEC_Ceor 571: #define Csum T_UNSPEC_Csum 572: #define Crot T_UNSPEC_Crot 573: #define word T_UNSPEC_word 574: #define bcount T_UNSPEC_bcount 575: 576: static long int Ceor, Csum, Crot, word, bcount; 577: 578: #define EN(c) ((int) ((c) + '!')) 579: #define DE(c) ((c) - '!') 580: #define AddToBuf(bufp, c) **bufp = c; (*bufp)++; 581: #define streq(s0, s1) strcmp(s0, s1) == 0 582: #define times85(x) ((((((x<<2)+x)<<2)+x)<<2)+x) 583: 584: 585: /* Decode ASCII-encoded byte c into binary representation and 586: * place into *bufp, advancing bufp 587: */ 588: static int 589: byte_atob(c, bufp) 590: register c; 591: char **bufp; 592: { 593: if (c == 'z') { 594: if (bcount != 0) 595: return(CONV_BADFMT); 596: else { 597: putbyte(0, bufp); 598: putbyte(0, bufp); 599: putbyte(0, bufp); 600: putbyte(0, bufp); 601: } 602: } else if ((c >= '!') && (c < ('!' + 85))) { 603: if (bcount == 0) { 604: word = DE(c); 605: ++bcount; 606: } else if (bcount < 4) { 607: word = times85(word); 608: word += DE(c); 609: ++bcount; 610: } else { 611: word = times85(word) + DE(c); 612: putbyte((int)((word >> 24) & 255), bufp); 613: putbyte((int)((word >> 16) & 255), bufp); 614: putbyte((int)((word >> 8) & 255), bufp); 615: putbyte((int)(word & 255), bufp); 616: word = 0; 617: bcount = 0; 618: } 619: } else 620: return(CONV_BADFMT); 621: return(CONV_SUCCESS); 622: } 623: 624: /* Compute checksum info and place c into *bufp, advancing bufp */ 625: static 626: putbyte(c, bufp) 627: register c; 628: char **bufp; 629: { 630: Ceor ^= c; 631: Csum += c; 632: Csum += 1; 633: if ((Crot & 0x80000000)) { 634: Crot <<= 1; 635: Crot += 1; 636: } else { 637: Crot <<= 1; 638: } 639: Crot += c; 640: AddToBuf(bufp, c); 641: } 642: 643: /* Read the ASCII-encoded data from inbuf, of length inbuflen, and convert 644: it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes; 645: outbuflen must be divisible by 4. (Note: this is because outbuf is filled 646: in 4 bytes at a time. If the actual data doesn't end on an even 4-byte 647: boundary, there will be no problem...it will be padded with 0 bytes, and 648: numbytes will indicate the correct number of bytes. The main point is 649: that since the buffer is filled in 4 bytes at a time, even if there is 650: not a full 4 bytes of data at the end, there has to be room to 0-pad the 651: data, so the buffer must be of size divisible by 4). Place the number of 652: output bytes in numbytes, and return a failure/success status */ 653: int 654: atob(inbuf, inbuflen, outbuf, outbuflen, numbytes) 655: char *inbuf; 656: int inbuflen; 657: char *outbuf; 658: int outbuflen; 659: int *numbytes; 660: { 661: int inc, nb; 662: long int oeor, osum, orot; 663: char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen]; 664: 665: if ( (outbuflen % 4) != 0) 666: return(CONV_BADBUFLEN); 667: Ceor = Csum = Crot = word = bcount = 0; 668: for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) { 669: if (outp > endoutp) 670: return(CONV_OVERFLOW); 671: if (*inp == 'x') { 672: inp +=2; 673: break; 674: } else { 675: if (byte_atob(*inp, &outp) == CONV_BADFMT) 676: return(CONV_BADFMT); 677: } 678: } 679: 680: /* Get byte count and checksum information from end of buffer */ 681: if(sscanf(inp, "%ld %lx %lx %lx", numbytes, &oeor, &osum, &orot) != 4) 682: return(CONV_BADFMT); 683: if ((oeor != Ceor) || (osum != Csum) || (orot != Crot)) 684: return(CONV_BADCKSUM); 685: return(CONV_SUCCESS); 686: } 687: 688: /* Encode binary byte c into ASCII representation and place into *bufp, 689: advancing bufp */ 690: static 691: byte_btoa(c, bufp) 692: register c; 693: char **bufp; 694: { 695: Ceor ^= c; 696: Csum += c; 697: Csum += 1; 698: if ((Crot & 0x80000000)) { 699: Crot <<= 1; 700: Crot += 1; 701: } else { 702: Crot <<= 1; 703: } 704: Crot += c; 705: 706: word <<= 8; 707: word |= c; 708: if (bcount == 3) { 709: if (word == 0) { 710: AddToBuf(bufp, 'z'); 711: } else { 712: register int tmp = 0; 713: register long int tmpword = word; 714: 715: if (tmpword < 0) { 716: /* Because some don't support unsigned long */ 717: tmp = 32; 718: tmpword -= (long)(85 * 85 * 85 * 85 * 32); 719: } 720: if (tmpword < 0) { 721: tmp = 64; 722: tmpword -= (long)(85 * 85 * 85 * 85 * 32); 723: } 724: AddToBuf(bufp, 725: EN((tmpword / (long)(85 * 85 * 85 * 85)) + tmp)); 726: tmpword %= (long)(85 * 85 * 85 * 85); 727: AddToBuf(bufp, EN(tmpword / (85 * 85 * 85))); 728: tmpword %= (85 * 85 * 85); 729: AddToBuf(bufp, EN(tmpword / (85 * 85))); 730: tmpword %= (85 * 85); 731: AddToBuf(bufp, EN(tmpword / 85)); 732: tmpword %= 85; 733: AddToBuf(bufp, EN(tmpword)); 734: } 735: bcount = 0; 736: } else { 737: bcount += 1; 738: } 739: } 740: 741: 742: /* 743: * Encode the binary data from inbuf, of length inbuflen, into a 744: * null-terminated ASCII representation in outbuf, not to exceed outbuflen 745: * bytes. Return success/failure status 746: */ 747: int 748: btoa(inbuf, inbuflen, outbuf, outbuflen) 749: char *inbuf; 750: int inbuflen; 751: char *outbuf; 752: int outbuflen; 753: { 754: long int inc, nb; 755: long int oeor, osum, orot; 756: char *inp, *outp = outbuf, *endoutp = &outbuf[outbuflen -1]; 757: 758: Ceor = Csum = Crot = word = bcount = 0; 759: for (inp = inbuf, inc = 0; inc < inbuflen; inp++, inc++) { 760: byte_btoa((unsigned char) (*inp), &outp); 761: if (outp >= endoutp) 762: return(CONV_OVERFLOW); 763: } 764: while (bcount != 0) { 765: byte_btoa(0, &outp); 766: if (outp >= endoutp) 767: return(CONV_OVERFLOW); 768: } 769: /* Put byte count and checksum information at end of buffer, delimited 770: by 'x' */ 771: (void) sprintf(outp, "x %ld %lx %lx %lx", inbuflen, Ceor, Csum, Crot); 772: if (&outp[strlen(outp) - 1] >= endoutp) 773: return(CONV_OVERFLOW); 774: else 775: return(CONV_SUCCESS); 776: } 777: #endif ALLOW_T_UNSPEC