3 Turn data structures into printable text. */
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
36 static char copyright[] =
37 "$Id: print.c,v 1.53.2.11 2004/06/17 20:54:39 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
42 char *quotify_string (const char *s, const char *file, int line)
48 for (sp = s; sp && *sp; sp++) {
51 else if (!isascii (*sp) || !isprint (*sp))
53 else if (*sp == '"' || *sp == '\\')
59 buf = dmalloc (len + 1, file, line);
62 for (sp = s; sp && *sp; sp++) {
65 else if (!isascii (*sp) || !isprint (*sp)) {
66 sprintf (nsp, "\\%03o",
67 *(const unsigned char *)sp);
69 } else if (*sp == '"' || *sp == '\\') {
80 char *quotify_buf (const unsigned char *s, unsigned len,
81 const char *file, int line)
87 for (i = 0; i < len; i++) {
90 else if (!isascii (s [i]) || !isprint (s [i]))
92 else if (s [i] == '"' || s [i] == '\\')
98 buf = dmalloc (nulen + 1, MDL);
101 for (i = 0; i < len; i++) {
104 else if (!isascii (s [i]) || !isprint (s [i])) {
105 sprintf (nsp, "\\%03o", s [i]);
107 } else if (s [i] == '"' || s [i] == '\\') {
118 char *print_base64 (const unsigned char *buf, unsigned len,
119 const char *file, int line)
125 static char to64 [] =
126 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
128 bl = ((len * 4 + 2) / 3) + 1;
129 b = dmalloc (bl + 1, file, line);
141 *s++ = to64 [extra << 4];
145 val = (extra << 8) + buf [i++];
150 *s++ = to64 [extra << 2];
154 val = (extra << 8) + buf [i++];
168 char *print_hw_addr (htype, hlen, data)
173 static char habuf [49];
181 for (i = 0; i < hlen; i++) {
182 sprintf (s, "%02x", data [i]);
191 void print_lease (lease)
197 log_debug (" Lease %s",
198 piaddr (lease -> ip_addr));
200 t = gmtime (&lease -> starts);
201 strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
202 log_debug (" start %s", tbuf);
204 t = gmtime (&lease -> ends);
205 strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
206 log_debug (" end %s", tbuf);
208 if (lease -> hardware_addr.hlen)
209 log_debug (" hardware addr = %s",
210 print_hw_addr (lease -> hardware_addr.hbuf [0],
211 lease -> hardware_addr.hlen - 1,
212 &lease -> hardware_addr.hbuf [1]));
213 log_debug (" host %s ",
214 lease -> host ? lease -> host -> name : "<none>");
217 #if defined (DEBUG_PACKET)
218 void dump_packet_option (struct option_cache *oc,
219 struct packet *packet,
221 struct client_state *client,
222 struct option_state *in_options,
223 struct option_state *cfg_options,
224 struct binding_scope **scope,
225 struct universe *u, void *foo)
227 const char *name, *dot;
228 struct data_string ds;
229 memset (&ds, 0, sizeof ds);
231 if (u != &dhcp_universe) {
238 if (evaluate_option_cache (&ds, packet, lease, client,
239 in_options, cfg_options, scope, oc, MDL)) {
240 log_debug (" option %s%s%s %s;\n",
241 name, dot, oc -> option -> name,
242 pretty_print_option (oc -> option,
243 ds.data, ds.len, 1, 1));
244 data_string_forget (&ds, MDL);
248 void dump_packet (tp)
251 struct dhcp_packet *tdp = tp -> raw;
253 log_debug ("packet length %d", tp -> packet_length);
254 log_debug ("op = %d htype = %d hlen = %d hops = %d",
255 tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
256 log_debug ("xid = %x secs = %ld flags = %x",
257 tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
258 log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
259 log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
260 log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
261 log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
262 log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
263 ((unsigned char *)(tdp -> chaddr)) [0],
264 ((unsigned char *)(tdp -> chaddr)) [1],
265 ((unsigned char *)(tdp -> chaddr)) [2],
266 ((unsigned char *)(tdp -> chaddr)) [3],
267 ((unsigned char *)(tdp -> chaddr)) [4],
268 ((unsigned char *)(tdp -> chaddr)) [5]);
269 log_debug ("filename = %s", tdp -> file);
270 log_debug ("server_name = %s", tdp -> sname);
271 if (tp -> options_valid) {
274 for (i = 0; i < tp -> options -> universe_count; i++) {
275 if (tp -> options -> universes [i]) {
276 option_space_foreach (tp, (struct lease *)0,
277 (struct client_state *)0,
278 (struct option_state *)0,
286 log_debug ("%s", "");
290 void dump_raw (buf, len)
291 const unsigned char *buf;
300 01234567890123456789012345678901234567890123456789012345678901234567890123
301 280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................
304 memset(lbuf, ' ', 79);
307 for (i = 0; i < len; i++) {
316 memset(lbuf, ' ', 79);
318 sprintf (lbuf, "%03x:", i);
320 } else if ((i & 7) == 0)
323 if(isprint(buf[i])) {
324 lbuf[56+(i%16)]=buf[i];
329 sprintf (&lbuf [lbix], " %02x", buf [i]);
341 void hash_dump (table)
342 struct hash_table *table;
345 struct hash_bucket *bp;
350 for (i = 0; i < table -> hash_count; i++) {
351 if (!table -> buckets [i])
353 log_info ("hash bucket %d:", i);
354 for (bp = table -> buckets [i]; bp; bp = bp -> next) {
356 dump_raw (bp -> name, bp -> len);
358 log_info ("%s", (const char *)bp -> name);
365 #define DECLARE_HEX_PRINTER(x) \
366 char *print_hex##x (len, data, limit) \
368 const u_int8_t *data; \
372 static char hex_buf##x [HBLEN + 1]; \
378 for (i = 0; i < (limit - 2) && i < len; i++) { \
379 if (!isascii (data [i]) || !isprint (data [i])) { \
380 for (i = 0; i < limit / 3 && i < len; i++) { \
381 sprintf (&hex_buf##x [i * 3], \
382 "%02x:", data [i]); \
384 hex_buf##x [i * 3 - 1] = 0; \
388 hex_buf##x [0] = '"'; \
392 memcpy (&hex_buf##x [1], data, i); \
393 hex_buf##x [i + 1] = '"'; \
394 hex_buf##x [i + 2] = 0; \
398 DECLARE_HEX_PRINTER (_1)
399 DECLARE_HEX_PRINTER (_2)
400 DECLARE_HEX_PRINTER (_3)
404 char *print_dotted_quads (len, data)
406 const u_int8_t *data;
408 static char dq_buf [DQLEN + 1];
417 /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe%
418 * The sprintf can't exceed 18 bytes, and since the loop enforces
419 * 21 bytes of space per iteration at no time can we exit the
420 * loop without at least 3 bytes spare.
423 sprintf (s, "%u.%u.%u.%u, ",
424 data [i], data [i + 1], data [i + 2], data [i + 3]);
427 } while ((s - &dq_buf [0] > DQLEN - 21) &&
436 char *print_dec_1 (val)
439 static char vbuf [32];
440 sprintf (vbuf, "%lu", val);
444 char *print_dec_2 (val)
447 static char vbuf [32];
448 sprintf (vbuf, "%lu", val);
452 static unsigned print_subexpression PROTO ((struct expression *,
455 static unsigned print_subexpression (expr, buf, len)
456 struct expression *expr;
463 switch (expr -> op) {
473 strcpy (buf, "(match)");
479 rv = 10 + strlen (expr -> data.check -> name);
481 sprintf (buf, "(check %s)",
482 expr -> data.check -> name);
490 strcpy (buf, "(eq ");
491 rv += print_subexpression (expr -> data.equal [0],
492 buf + rv, len - rv - 2);
494 rv += print_subexpression (expr -> data.equal [1],
495 buf + rv, len - rv - 1);
505 strcpy (buf, "(neq ");
506 rv += print_subexpression (expr -> data.equal [0],
507 buf + rv, len - rv - 2);
509 rv += print_subexpression (expr -> data.equal [1],
510 buf + rv, len - rv - 1);
520 strcpy (buf, "(substr ");
521 rv += print_subexpression (expr -> data.substring.expr,
522 buf + rv, len - rv - 3);
524 rv += print_subexpression
525 (expr -> data.substring.offset,
526 buf + rv, len - rv - 2);
528 rv += print_subexpression (expr -> data.substring.len,
529 buf + rv, len - rv - 1);
539 strcpy (buf, "(suffix ");
540 rv += print_subexpression (expr -> data.suffix.expr,
541 buf + rv, len - rv - 2);
544 rv += print_subexpression (expr -> data.suffix.len,
545 buf + rv, len - rv - 1);
556 strcpy (buf, "(concat ");
557 rv += print_subexpression (expr -> data.concat [0],
558 buf + rv, len - rv - 2);
560 rv += print_subexpression (expr -> data.concat [1],
561 buf + rv, len - rv - 1);
568 case expr_pick_first_value:
571 strcpy (buf, "(pick1st ");
572 rv += print_subexpression
573 (expr -> data.pick_first_value.car,
574 buf + rv, len - rv - 2);
576 rv += print_subexpression
577 (expr -> data.pick_first_value.cdr,
578 buf + rv, len - rv - 1);
585 case expr_host_lookup:
586 rv = 15 + strlen (expr -> data.host_lookup -> hostname);
588 sprintf (buf, "(dns-lookup %s)",
589 expr -> data.host_lookup -> hostname);
600 strcpy (&buf [1], s);
603 rv += print_subexpression (expr -> data.and [0],
604 buf + rv, len - rv - 2);
606 rv += print_subexpression (expr -> data.and [1],
607 buf + rv, len - rv - 1);
638 case expr_binary_and:
646 case expr_binary_xor:
653 strcpy (buf, "(not ");
654 rv += print_subexpression (expr -> data.not,
655 buf + rv, len - rv - 1);
662 case expr_config_option:
669 rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
670 strlen (expr -> data.option -> universe -> name));
672 sprintf (buf, "(option %s.%s)",
673 expr -> data.option -> universe -> name,
674 expr -> data.option -> name);
681 strcpy (buf, "(hardware)");
689 strcpy (buf, "(substr ");
690 rv += print_subexpression (expr -> data.packet.offset,
691 buf + rv, len - rv - 2);
693 rv += print_subexpression (expr -> data.packet.len,
694 buf + rv, len - rv - 1);
701 case expr_const_data:
702 s = print_hex_1 (expr -> data.const_data.len,
703 expr -> data.const_data.data, len);
707 strncpy (buf, s, rv);
711 case expr_encapsulate:
713 strcpy (buf, "(encapsulate ");
714 rv += expr -> data.encapsulate.len;
718 (const char *)expr -> data.encapsulate.data, rv - 13);
723 case expr_extract_int8:
726 strcpy (buf, "(int8 ");
727 rv += print_subexpression (expr -> data.extract_int,
728 buf + rv, len - rv - 1);
735 case expr_extract_int16:
738 strcpy (buf, "(int16 ");
739 rv += print_subexpression (expr -> data.extract_int,
740 buf + rv, len - rv - 1);
747 case expr_extract_int32:
750 strcpy (buf, "(int32 ");
751 rv += print_subexpression (expr -> data.extract_int,
752 buf + rv, len - rv - 1);
759 case expr_encode_int8:
762 strcpy (buf, "(to-int8 ");
763 rv += print_subexpression (expr -> data.encode_int,
764 buf + rv, len - rv - 1);
771 case expr_encode_int16:
774 strcpy (buf, "(to-int16 ");
775 rv += print_subexpression (expr -> data.encode_int,
776 buf + rv, len - rv - 1);
783 case expr_encode_int32:
786 strcpy (buf, "(to-int32 ");
787 rv += print_subexpression (expr -> data.encode_int,
788 buf + rv, len - rv - 1);
796 s = print_dec_1 (expr -> data.const_int);
805 rv = 10 + (strlen (expr -> data.option -> name) +
806 strlen (expr -> data.option -> universe -> name));
808 sprintf (buf, "(exists %s.%s)",
809 expr -> data.option -> universe -> name,
810 expr -> data.option -> name);
815 case expr_variable_exists:
816 rv = 10 + strlen (expr -> data.variable);
818 sprintf (buf, "(defined %s)", expr -> data.variable);
823 case expr_variable_reference:
824 rv = strlen (expr -> data.variable);
826 sprintf (buf, "%s", expr -> data.variable);
841 case expr_leased_address:
842 s = "leased-address";
845 case expr_client_state:
849 case expr_host_decl_name:
850 s = "host-decl-name";
853 case expr_lease_time:
872 strcpy (buf, "(reverse ");
873 rv += print_subexpression (expr -> data.reverse.width,
874 buf + rv, len - rv - 2);
876 rv += print_subexpression (expr -> data.reverse.buffer,
877 buf + rv, len - rv - 1);
884 case expr_binary_to_ascii:
887 strcpy (buf, "(b2a ");
888 rv += print_subexpression (expr -> data.b2a.base,
889 buf + rv, len - rv - 4);
891 rv += print_subexpression (expr -> data.b2a.width,
892 buf + rv, len - rv - 3);
894 rv += print_subexpression (expr -> data.b2a.seperator,
895 buf + rv, len - rv - 2);
897 rv += print_subexpression (expr -> data.b2a.buffer,
898 buf + rv, len - rv - 1);
905 case expr_dns_transaction:
909 strcpy (&buf [1], "ns-update ");
910 while (len < rv + 2) {
911 rv += print_subexpression
912 (expr -> data.dns_transaction.car,
913 buf + rv, len - rv - 2);
915 expr = expr -> data.dns_transaction.cdr;
931 case expr_ns_not_exists:
940 if (len > strlen (s) + 1) {
945 s = print_dec_1 (expr -> data.ns_add.rrclass);
946 if (len > rv + strlen (s) + left) {
947 strcpy (&buf [rv], s);
948 rv += strlen (&buf [rv]);
952 s = print_dec_1 (expr -> data.ns_add.rrtype);
953 if (len > rv + strlen (s) + left) {
954 strcpy (&buf [rv], s);
955 rv += strlen (&buf [rv]);
959 rv += print_subexpression
960 (expr -> data.ns_add.rrname,
961 buf + rv, len - rv - left);
964 rv += print_subexpression
965 (expr -> data.ns_add.rrdata,
966 buf + rv, len - rv - left);
969 rv += print_subexpression
970 (expr -> data.ns_add.ttl,
971 buf + rv, len - rv - left);
980 strcpy (buf, "(null)");
985 rv = 12 + strlen (expr -> data.funcall.name);
987 strcpy (buf, "(funcall ");
988 strcpy (buf + 9, expr -> data.funcall.name);
990 rv += print_subexpression
991 (expr -> data.funcall.arglist, buf + rv,
1000 rv = print_subexpression (expr -> data.arg.val, buf, len);
1001 if (expr -> data.arg.next && rv + 2 < len) {
1003 rv += print_subexpression (expr -> data.arg.next,
1013 struct string_list *foo;
1014 strcpy (buf, "(function");
1015 for (foo = expr -> data.func -> args;
1016 foo; foo = foo -> next) {
1017 if (len > rv + 2 + strlen (foo -> string)) {
1019 strcpy (&buf [rv], foo -> string);
1020 rv += strlen (foo -> string);
1031 void print_expression (name, expr)
1033 struct expression *expr;
1037 print_subexpression (expr, buf, sizeof buf);
1038 log_info ("%s: %s", name, buf);
1041 int token_print_indent_concat (FILE *file, int col, int indent,
1043 const char *suffix, ...)
1050 va_start (list, suffix);
1051 s = va_arg (list, char *);
1055 s = va_arg (list, char *);
1059 t = dmalloc (len + 1, MDL);
1061 log_fatal ("token_print_indent: no memory for copy buffer");
1063 va_start (list, suffix);
1064 s = va_arg (list, char *);
1073 len = token_print_indent (file, col, indent,
1079 int token_indent_data_string (FILE *file, int col, int indent,
1080 const char *prefix, const char *suffix,
1081 struct data_string *data)
1087 /* See if this is just ASCII. */
1088 for (i = 0; i < data -> len; i++)
1089 if (!isascii (data -> data [i]) ||
1090 !isprint (data -> data [i]))
1093 /* If we have a purely ASCII string, output it as text. */
1094 if (i == data -> len) {
1095 char *buf = dmalloc (data -> len + 3, MDL);
1098 memcpy (buf + 1, data -> data, data -> len);
1099 buf [data -> len + 1] = '"';
1100 buf [data -> len + 2] = 0;
1101 i = token_print_indent (file, col, indent,
1102 prefix, suffix, buf);
1108 for (i = 0; i < data -> len; i++) {
1109 sprintf (obuf, "%2.2x", data -> data [i]);
1110 col = token_print_indent (file, col, indent,
1111 i == 0 ? prefix : "",
1112 (i + 1 == data -> len
1115 if (i + 1 != data -> len)
1116 col = token_print_indent (file, col, indent,
1117 prefix, suffix, ":");
1122 int token_print_indent (FILE *file, int col, int indent,
1124 const char *suffix, const char *buf)
1126 int len = strlen (buf) + strlen (prefix);
1127 if (col + len > 79) {
1128 if (indent + len < 79) {
1129 indent_spaces (file, indent);
1132 indent_spaces (file, col);
1133 col = len > 79 ? 0 : 79 - len - 1;
1135 } else if (prefix && *prefix) {
1136 fputs (prefix, file);
1137 col += strlen (prefix);
1141 if (suffix && *suffix) {
1142 if (col + strlen (suffix) > 79) {
1143 indent_spaces (file, indent);
1146 fputs (suffix, file);
1147 col += strlen (suffix);
1153 void indent_spaces (FILE *file, int indent)
1157 for (i = 0; i < indent; i++)
1161 #if defined (NSUPDATE)
1162 void print_dns_status (int status, ns_updque *uq)
1165 char *s = &obuf [0], *end = &obuf [1022];
1169 const char *predicate = "if", *en, *op;
1172 for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) {
1175 switch (u -> r_opcode)
1178 op = "rrset doesn't exist";
1182 op = "rrset exists";
1186 op = "domain doesn't exist";
1190 op = "domain exists";
1208 if (s != &obuf [0] && s + 1 < end)
1210 if (s + strlen (op) < end) {
1215 if (s != &obuf [0] && s + 1 < end)
1217 if (s + strlen (predicate) < end) {
1218 strcpy (s, predicate);
1226 if (s + strlen (u -> r_dname) < end) {
1227 strcpy (s, u -> r_dname);
1234 /* 27 is as big as a ttl can get. */
1237 (unsigned long)(u -> r_ttl));
1241 switch (u -> r_class) {
1255 if (s + strlen (en) < end) {
1261 switch (u -> r_type) {
1284 if (s + strlen (en) < end) {
1293 if (u -> r_type == T_TXT) {
1297 if(u->r_type == T_KEY) {
1298 strcat(s, "<keydata>");
1299 s+=strlen("<keydata>");
1302 if (s + u -> r_size < end) {
1303 memcpy (s, u -> r_data, u -> r_size);
1305 if (u -> r_type == T_TXT) {
1315 if (s + strlen (op) < end) {
1320 if (u == ISC_LIST_TAIL (*uq))
1323 if (s == &obuf [0]) {
1324 strcpy (s, "empty update");
1327 if (status == NOERROR)
1331 en = isc_result_totext (status);
1335 en = "resolver failed";
1339 en = "format error";
1348 en = "not authorized";
1352 en = "not implemented";
1356 en = "not a single valid zone";
1360 en = "no such domain";
1364 en = "no such record";
1372 en = "server failed";
1376 en = "domain exists";
1380 en = "record exists";
1384 en = "unknown error";
1393 if (s + strlen (en) < end) {
1401 log_error ("%s", obuf);
1403 log_info ("%s", obuf);
1405 #endif /* NSUPDATE */