3 * dumpscan - routines for scanning and manipulating AFS volume dumps
5 * Copyright (c) 1998 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
29 #include <sys/types.h>
30 #include <sys/socket.h>
33 #include <netinet/in.h>
41 static char spbuf[SPBUFLEN + 1] = "";
46 /* Generate an ASCII representation of an integer <val>, as follows:
47 * <base> indicates the base to be used (2-36)
48 * <uc> is nonzero if letter digits should be uppercase
49 * <prec> is the minimum number of digits
50 * The resulting number is stored in <buf>, which must be long enough
51 * to receive it. The minimum length is <prec> or ceil(log{base}(val)),
52 * whichever is larger, plus room for a trailing NUL.
54 static void mkint(char *buf, unsigned long val, int base, int uc, int prec)
60 val = (val - dig) / base;
61 if (dig < 10) dig = dig + '0';
62 else if (uc) dig = dig + 'A' - 10;
63 else dig = dig + 'a' - 10;
66 while (len < prec) buf[len++] = '0';
67 for (i = 0; i < (len + 1) / 2; i++) {
69 buf[i] = buf[len - i - 1];
70 buf[len - i - 1] = dig;
76 /* Write spaces faster than one at a time */
77 static afs_uint32 wsp(XFILE *X, int count)
84 for (x = spbuf, i = SPBUFLEN; i; x++, i--) *x = ' ';
87 while (count > SPBUFLEN) {
88 err = xfwrite(X, spbuf, SPBUFLEN);
92 if (count > 0) return xfwrite(X, spbuf, count);
97 /* This function is a mostly-complete implementation of snprintf,
98 * with the following features:
100 * - Actually obeys the length limit, which (unfortunately) many
101 * implementations of snprintf do not.
103 * - Supports all the standard format specifiers for integers
104 * (d, i, o, u, x, X), floating-point values (f, e, E, g, G),
105 * and strings and characters (c, s, %), plus a few unusual
106 * but useful ones described below.
108 * - Supports all the standard flags (-, 0, +, space, #). These
109 * flags are ignored if used when they are not appropriate.
111 * - Supports the standard size modifiers for short (h), long (h),
112 * and double (L) arguments. These modifiers are ignored if used
113 * when they are not appropriate.
115 * - Supports minimum field width and precision, where appropriate,
116 * including the use of '*' to specify a value given as an argument
117 * instead of in the format string. There is a maximum precision
120 * - At present, the 'p' specifier for printing pointers is not
121 * implemented, because it is inherently non-portable and thus
122 * can be implemented correctly only by the compiler's run-time
125 * - Floating-point specifier (%e, %f, %g) are implemented by
126 * calling the standard sprintf, and thus may be unsafe.
128 * - The '%...$' notation is used primarily when the format string
129 * is specified by the user, who knows but cannot change the order
130 * of the arguments. Such usage is inherently dangerous and
131 * insecure; thus, it is not supported.
133 * The custom format specifier '%I' is supported. This specifier
134 * takes as its argument an unsigned long integer containing an
135 * IPv4 address in network byte order. The address is rendered
136 * either as a hostname or as a dotted quad, as follows:
138 * - If precision is nonzero or unspecified, a hostname lookup
139 * is attempted; if it is successful, the hostname is printed.
140 * If the hostname lookup fails, the address is printed in
141 * dotted-quad notation.
143 * - If precision is explicitly specified as 0, then the hostname
144 * lookup is skipped, and dotted-quad notation is always used.
146 * - If a hostname is to be printed:
147 * + The precision controls the maximum number of characters
148 * printed, as with %s.
149 * + If the '#' flag is specified, any letters in the hostname
150 * will be forced to lower case before printing.
151 * + If the '+' flag is specified, any letters in the hostname
152 * will be forced to upper case before printing. If both
153 * '#' and '+' are given, the '+' flag will be ignored.
154 * + The '0' and ' ' flags have no effect.
156 * - If a dotted quad is to be printed:
157 * + The precision has no effect; dotted quads are always
158 * 7 to 12 characters in length, depending on the value
159 * to be printed and the format flags used.
160 * + If the '0' flag is given, each field (byte) of the address
161 * will be padded with '0' on the left to three digits.
162 * + If the ' ' flag is given, each field (byte) of the address
163 * will be padded with spaces on the left to three digits. If
164 * both '0' and ' ' are given, the ' ' flag will be ignored.
165 * + The '#' and '+' flags have no effect.
168 afs_uint32 vxfprintf(XFILE *X, char *fmt, va_list ap)
170 unsigned int width, precision, haveprec, len;
171 int ljust, plsign, spsign, altform, zfill;
172 int hflag, lflag, count, *countp, j;
173 char *x, *y, *lit = 0, xbuf[MAXPREC + 21], fbuf[20];
191 if ((err = xfwrite(X, lit, fmt - lit))) return err;
195 /** Found a format specifier **/
196 ljust = plsign = spsign = altform = zfill = 0;
197 width = precision = haveprec = 0;
201 /* parse format flags */
204 case '-': ljust = 1; fmt++; continue; /* left justify */
205 case '+': plsign = 1; fmt++; continue; /* use + or - */
206 case ' ': spsign = 1; fmt++; continue; /* use space or - */
207 case '#': altform = 1; fmt++; continue; /* alternate form */
208 case '0': zfill = 1; fmt++; continue; /* pad with 0 */
214 /* parse minimum width */
216 width = va_arg(ap, int);
218 } else while (isdigit(*fmt)) {
219 width = (width * 10) + (*fmt - '0');
223 /* parse precision */
228 precision = va_arg(ap, int);
230 } else while (isdigit(*fmt)) {
231 precision = (precision * 10) + (*fmt - '0');
236 /* parse size flags */
239 case 'h': hflag = 1; fmt++; continue; /* short argument */
240 case 'l': lflag = 1; fmt++; continue; /* long argument */
246 /* parse format specifier */
254 FVAL = va_arg(ap, double);
255 sprintf(fbuf, "%%%s%s.*L%c", plsign ? "+" : (spsign ? " " : ""),
256 altform ? "#" : "", fmt[-1]);
257 if (!haveprec) precision = 6;
258 if (precision > MAXPREC) precision = MAXPREC;
259 sprintf(xbuf, fbuf, precision, FVAL);
265 case 'd': /* signed decimal integer */
266 if (lflag) SVAL = va_arg(ap, long);
267 else if (hflag) SVAL = va_arg(ap, int);
268 else SVAL = va_arg(ap, int);
269 UVAL = (SVAL < 0) ? -SVAL : SVAL;
271 if (SVAL < 0) xbuf[0] = '-';
272 else if (plsign) xbuf[0] = '+';
273 else if (spsign) xbuf[0] = ' ';
277 if (zfill && !ljust) precision = width - !!xbuf[0];
279 if (precision < 1 + !!xbuf[0]) precision = 1 + !!xbuf[0];
281 if (precision > MAXPREC) precision = MAXPREC;
283 mkint(xbuf + 1, UVAL, 10, 0, precision);
289 case 'o': /* unsigned octal integer */
290 if (lflag) UVAL = va_arg(ap, unsigned long);
291 else if (hflag) UVAL = va_arg(ap, unsigned int);
292 else UVAL = va_arg(ap, unsigned int);
297 if (zfill && !ljust) precision = width;
300 if (precision > MAXPREC) precision = MAXPREC;
302 mkint(xbuf + 1, UVAL, 8, 0, precision);
303 x = xbuf + (xbuf[1] == '0' || !altform);
307 case 'u': /* unsigned decimal integer */
308 if (lflag) UVAL = va_arg(ap, unsigned long);
309 else if (hflag) UVAL = va_arg(ap, unsigned int);
310 else UVAL = va_arg(ap, unsigned int);
313 if (zfill && !ljust) precision = width;
316 if (precision > MAXPREC) precision = MAXPREC;
318 mkint(xbuf, UVAL, 10, 0, precision);
324 case 'X': /* unsigned hexadecimal integer */
325 if (lflag) UVAL = va_arg(ap, unsigned long);
326 else if (hflag) UVAL = va_arg(ap, unsigned int);
327 else UVAL = va_arg(ap, unsigned int);
333 if (zfill && !ljust) precision = width;
336 if (precision > MAXPREC) precision = MAXPREC;
338 mkint(xbuf + 2, UVAL, 16, 0, precision);
339 x = xbuf + ((altform && UVAL) ? 0 : 2);
343 case '%': /* literal % */
350 case 'c': /* character */
351 xbuf[0] = va_arg(ap, int);
357 case 's': /* string */
358 x = va_arg(ap, char *);
359 if (!x) x = "<null>";
361 if (haveprec && precision < len) len = precision;
364 case 'I': /* IP address:
365 * value is provided as a network-order unsigned long integer
366 * precision specifies max hostname length, as for %s
367 * if precision is explicitly 0, no hostname lookup is done
368 * if 0fill specified, IPaddr fields are 0-filled to 3 digits
369 * if spsign specified, IPaddr fields are space-filled to 3 digits
371 UVAL = va_arg(ap, unsigned long);
373 /* XXX: add support for an application-provided function
374 * for doing hostname lookups. We don't do it automatically
375 * because on some platforms that would prevent us from
376 * being fully statically linked.
378 if (haveprec && !precision) he = 0;
379 else he = gethostbyaddr((char *)&ia, 4, AF_INET);
383 if (haveprec && precision < len) len = precision;
385 for (y = x; *y; y++) if (isupper(*y)) *y = tolower(*y);
387 for (y = x; *y; y++) if (islower(*y)) *y = toupper(*y);
390 if (zfill) x = "%03u.%03u.%03u.%03u";
391 else if (spsign) x = "%3u.%3u.%3u.%3u";
392 else x = "%u.%u.%u.%u";
394 (UVAL & 0xff000000) >> 24, (UVAL & 0x00ff0000) >> 16,
395 (UVAL & 0x0000ff00) >> 8, (UVAL & 0x000000ff));
401 case 'n': /* report count so far */
403 lcountp = va_arg(ap, long *);
406 hcountp = va_arg(ap, short *);
409 countp = va_arg(ap, int *);
414 default: /* unknown specifier */
418 /* render the results */
419 if (!width) width = len;
421 if (j > 0) count += j;
424 if (!ljust && (err = wsp(X, j))) return err;
425 if ((err = xfwrite(X, x, len))) return err;
426 if (ljust && (err = wsp(X, j))) return err;
428 if (lit && (err = xfwrite(X, lit, fmt - lit))) return err;
435 afs_uint32 xfprintf(XFILE *X, char *fmt, ...)
441 err = vxfprintf(X, fmt, ap);