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