3 Turn data structures into printable text. */
6 * Copyright (c) 1995-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
45 static char copyright[] =
46 "$Id: print.c,v 1.53.2.7 2002/11/17 02:26:59 dhankins Exp $ Copyright (c) 1995-2002 The Internet Software Consortium. All rights reserved.\n";
51 char *quotify_string (const char *s, const char *file, int line)
57 for (sp = s; sp && *sp; sp++) {
60 else if (!isascii (*sp) || !isprint (*sp))
62 else if (*sp == '"' || *sp == '\\')
68 buf = dmalloc (len + 1, file, line);
71 for (sp = s; sp && *sp; sp++) {
74 else if (!isascii (*sp) || !isprint (*sp)) {
75 sprintf (nsp, "\\%03o",
76 *(const unsigned char *)sp);
78 } else if (*sp == '"' || *sp == '\\') {
89 char *quotify_buf (const unsigned char *s, unsigned len,
90 const char *file, int line)
96 for (i = 0; i < len; i++) {
99 else if (!isascii (s [i]) || !isprint (s [i]))
101 else if (s [i] == '"' || s [i] == '\\')
107 buf = dmalloc (nulen + 1, MDL);
110 for (i = 0; i < len; i++) {
113 else if (!isascii (s [i]) || !isprint (s [i])) {
114 sprintf (nsp, "\\%03o", s [i]);
116 } else if (s [i] == '"' || s [i] == '\\') {
127 char *print_base64 (const unsigned char *buf, unsigned len,
128 const char *file, int line)
134 static char to64 [] =
135 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
137 bl = ((len * 4 + 2) / 3) + 1;
138 b = dmalloc (bl + 1, file, line);
150 *s++ = to64 [extra << 4];
154 val = (extra << 8) + buf [i++];
159 *s++ = to64 [extra << 2];
163 val = (extra << 8) + buf [i++];
177 char *print_hw_addr (htype, hlen, data)
182 static char habuf [49];
190 for (i = 0; i < hlen; i++) {
191 sprintf (s, "%02x", data [i]);
200 void print_lease (lease)
206 log_debug (" Lease %s",
207 piaddr (lease -> ip_addr));
209 t = gmtime (&lease -> starts);
210 strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
211 log_debug (" start %s", tbuf);
213 t = gmtime (&lease -> ends);
214 strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
215 log_debug (" end %s", tbuf);
217 if (lease -> hardware_addr.hlen)
218 log_debug (" hardware addr = %s",
219 print_hw_addr (lease -> hardware_addr.hbuf [0],
220 lease -> hardware_addr.hlen - 1,
221 &lease -> hardware_addr.hbuf [1]));
222 log_debug (" host %s ",
223 lease -> host ? lease -> host -> name : "<none>");
227 void dump_packet_option (struct option_cache *oc,
228 struct packet *packet,
230 struct client_state *client,
231 struct option_state *in_options,
232 struct option_state *cfg_options,
233 struct binding_scope **scope,
234 struct universe *u, void *foo)
236 const char *name, *dot;
237 struct data_string ds;
238 memset (&ds, 0, sizeof ds);
240 if (u != &dhcp_universe) {
247 if (evaluate_option_cache (&ds, packet, lease, client,
248 in_options, cfg_options, scope, oc, MDL)) {
249 log_debug (" option %s%s%s %s;\n",
250 name, dot, oc -> option -> name,
251 pretty_print_option (oc -> option,
252 ds.data, ds.len, 1, 1));
253 data_string_forget (&ds, MDL);
257 void dump_packet (tp)
260 struct dhcp_packet *tdp = tp -> raw;
262 log_debug ("packet length %d", tp -> packet_length);
263 log_debug ("op = %d htype = %d hlen = %d hops = %d",
264 tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
265 log_debug ("xid = %x secs = %ld flags = %x",
266 tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
267 log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
268 log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
269 log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
270 log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
271 log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
272 ((unsigned char *)(tdp -> chaddr)) [0],
273 ((unsigned char *)(tdp -> chaddr)) [1],
274 ((unsigned char *)(tdp -> chaddr)) [2],
275 ((unsigned char *)(tdp -> chaddr)) [3],
276 ((unsigned char *)(tdp -> chaddr)) [4],
277 ((unsigned char *)(tdp -> chaddr)) [5]);
278 log_debug ("filename = %s", tdp -> file);
279 log_debug ("server_name = %s", tdp -> sname);
280 if (tp -> options_valid) {
283 for (i = 0; i < tp -> options -> universe_count; i++) {
284 if (tp -> options -> universes [i]) {
285 option_space_foreach (tp, (struct lease *)0,
286 (struct client_state *)0,
287 (struct option_state *)0,
295 log_debug ("%s", "");
299 void dump_raw (buf, len)
300 const unsigned char *buf;
309 for (i = 0; i < len; i++) {
313 sprintf (lbuf, "%03x:", i);
315 } else if ((i & 7) == 0)
317 sprintf (&lbuf [lbix], " %02x", buf [i]);
323 void hash_dump (table)
324 struct hash_table *table;
327 struct hash_bucket *bp;
332 for (i = 0; i < table -> hash_count; i++) {
333 if (!table -> buckets [i])
335 log_info ("hash bucket %d:", i);
336 for (bp = table -> buckets [i]; bp; bp = bp -> next) {
338 dump_raw (bp -> name, bp -> len);
340 log_info ((const char *)bp -> name);
347 #define DECLARE_HEX_PRINTER(x) \
348 char *print_hex##x (len, data, limit) \
350 const u_int8_t *data; \
354 static char hex_buf##x [HBLEN + 1]; \
360 for (i = 0; i < (limit - 2) && i < len; i++) { \
361 if (!isascii (data [i]) || !isprint (data [i])) { \
362 for (i = 0; i < limit / 3 && i < len; i++) { \
363 sprintf (&hex_buf##x [i * 3], \
364 "%02x:", data [i]); \
366 hex_buf##x [i * 3 - 1] = 0; \
370 hex_buf##x [0] = '"'; \
374 memcpy (&hex_buf##x [1], data, i); \
375 hex_buf##x [i + 1] = '"'; \
376 hex_buf##x [i + 2] = 0; \
380 DECLARE_HEX_PRINTER (_1)
381 DECLARE_HEX_PRINTER (_2)
382 DECLARE_HEX_PRINTER (_3)
386 char *print_dotted_quads (len, data)
388 const u_int8_t *data;
390 static char dq_buf [DQLEN + 1];
400 sprintf (s, "%d.%d.%d.%d, ",
401 data [i], data [i + 1], data [i + 2], data [i + 3]);
404 } while ((s - &dq_buf [0] > DQLEN - 21) &&
413 char *print_dec_1 (val)
416 static char vbuf [32];
417 sprintf (vbuf, "%lu", val);
421 char *print_dec_2 (val)
424 static char vbuf [32];
425 sprintf (vbuf, "%lu", val);
429 static unsigned print_subexpression PROTO ((struct expression *,
432 static unsigned print_subexpression (expr, buf, len)
433 struct expression *expr;
440 switch (expr -> op) {
450 strcpy (buf, "(match)");
456 rv = 10 + strlen (expr -> data.check -> name);
458 sprintf (buf, "(check %s)",
459 expr -> data.check -> name);
467 strcpy (buf, "(eq ");
468 rv += print_subexpression (expr -> data.equal [0],
469 buf + rv, len - rv - 2);
471 rv += print_subexpression (expr -> data.equal [1],
472 buf + rv, len - rv - 1);
482 strcpy (buf, "(neq ");
483 rv += print_subexpression (expr -> data.equal [0],
484 buf + rv, len - rv - 2);
486 rv += print_subexpression (expr -> data.equal [1],
487 buf + rv, len - rv - 1);
497 strcpy (buf, "(substr ");
498 rv += print_subexpression (expr -> data.substring.expr,
499 buf + rv, len - rv - 3);
501 rv += print_subexpression
502 (expr -> data.substring.offset,
503 buf + rv, len - rv - 2);
505 rv += print_subexpression (expr -> data.substring.len,
506 buf + rv, len - rv - 1);
516 strcpy (buf, "(suffix ");
517 rv += print_subexpression (expr -> data.suffix.expr,
518 buf + rv, len - rv - 2);
521 rv += print_subexpression (expr -> data.suffix.len,
522 buf + rv, len - rv - 1);
533 strcpy (buf, "(concat ");
534 rv += print_subexpression (expr -> data.concat [0],
535 buf + rv, len - rv - 2);
537 rv += print_subexpression (expr -> data.concat [1],
538 buf + rv, len - rv - 1);
545 case expr_pick_first_value:
548 strcpy (buf, "(pick1st ");
549 rv += print_subexpression
550 (expr -> data.pick_first_value.car,
551 buf + rv, len - rv - 2);
553 rv += print_subexpression
554 (expr -> data.pick_first_value.cdr,
555 buf + rv, len - rv - 1);
562 case expr_host_lookup:
563 rv = 15 + strlen (expr -> data.host_lookup -> hostname);
565 sprintf (buf, "(dns-lookup %s)",
566 expr -> data.host_lookup -> hostname);
577 strcpy (&buf [1], s);
580 rv += print_subexpression (expr -> data.and [0],
581 buf + rv, len - rv - 2);
583 rv += print_subexpression (expr -> data.and [1],
584 buf + rv, len - rv - 1);
615 case expr_binary_and:
623 case expr_binary_xor:
630 strcpy (buf, "(not ");
631 rv += print_subexpression (expr -> data.not,
632 buf + rv, len - rv - 1);
639 case expr_config_option:
646 rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
647 strlen (expr -> data.option -> universe -> name));
649 sprintf (buf, "(option %s.%s)",
650 expr -> data.option -> universe -> name,
651 expr -> data.option -> name);
658 strcpy (buf, "(hardware)");
666 strcpy (buf, "(substr ");
667 rv += print_subexpression (expr -> data.packet.offset,
668 buf + rv, len - rv - 2);
670 rv += print_subexpression (expr -> data.packet.len,
671 buf + rv, len - rv - 1);
678 case expr_const_data:
679 s = print_hex_1 (expr -> data.const_data.len,
680 expr -> data.const_data.data, len);
684 strncpy (buf, s, rv);
688 case expr_encapsulate:
690 strcpy (buf, "(encapsulate ");
691 rv += expr -> data.encapsulate.len;
695 (const char *)expr -> data.encapsulate.data, rv - 13);
700 case expr_extract_int8:
703 strcpy (buf, "(int8 ");
704 rv += print_subexpression (expr -> data.extract_int,
705 buf + rv, len - rv - 1);
712 case expr_extract_int16:
715 strcpy (buf, "(int16 ");
716 rv += print_subexpression (expr -> data.extract_int,
717 buf + rv, len - rv - 1);
724 case expr_extract_int32:
727 strcpy (buf, "(int32 ");
728 rv += print_subexpression (expr -> data.extract_int,
729 buf + rv, len - rv - 1);
736 case expr_encode_int8:
739 strcpy (buf, "(to-int8 ");
740 rv += print_subexpression (expr -> data.encode_int,
741 buf + rv, len - rv - 1);
748 case expr_encode_int16:
751 strcpy (buf, "(to-int16 ");
752 rv += print_subexpression (expr -> data.encode_int,
753 buf + rv, len - rv - 1);
760 case expr_encode_int32:
763 strcpy (buf, "(to-int32 ");
764 rv += print_subexpression (expr -> data.encode_int,
765 buf + rv, len - rv - 1);
773 s = print_dec_1 (expr -> data.const_int);
782 rv = 10 + (strlen (expr -> data.option -> name) +
783 strlen (expr -> data.option -> universe -> name));
785 sprintf (buf, "(exists %s.%s)",
786 expr -> data.option -> universe -> name,
787 expr -> data.option -> name);
792 case expr_variable_exists:
793 rv = 10 + strlen (expr -> data.variable);
795 sprintf (buf, "(defined %s)", expr -> data.variable);
800 case expr_variable_reference:
801 rv = strlen (expr -> data.variable);
803 sprintf (buf, "%s", expr -> data.variable);
818 case expr_leased_address:
819 s = "leased-address";
822 case expr_client_state:
826 case expr_host_decl_name:
827 s = "host-decl-name";
830 case expr_lease_time:
849 strcpy (buf, "(reverse ");
850 rv += print_subexpression (expr -> data.reverse.width,
851 buf + rv, len - rv - 2);
853 rv += print_subexpression (expr -> data.reverse.buffer,
854 buf + rv, len - rv - 1);
861 case expr_binary_to_ascii:
864 strcpy (buf, "(b2a ");
865 rv += print_subexpression (expr -> data.b2a.base,
866 buf + rv, len - rv - 4);
868 rv += print_subexpression (expr -> data.b2a.width,
869 buf + rv, len - rv - 3);
871 rv += print_subexpression (expr -> data.b2a.seperator,
872 buf + rv, len - rv - 2);
874 rv += print_subexpression (expr -> data.b2a.buffer,
875 buf + rv, len - rv - 1);
882 case expr_dns_transaction:
886 strcpy (&buf [1], "ns-update ");
887 while (len < rv + 2) {
888 rv += print_subexpression
889 (expr -> data.dns_transaction.car,
890 buf + rv, len - rv - 2);
892 expr = expr -> data.dns_transaction.cdr;
908 case expr_ns_not_exists:
917 if (len > strlen (s) + 1) {
922 s = print_dec_1 (expr -> data.ns_add.rrclass);
923 if (len > rv + strlen (s) + left) {
924 strcpy (&buf [rv], s);
925 rv += strlen (&buf [rv]);
929 s = print_dec_1 (expr -> data.ns_add.rrtype);
930 if (len > rv + strlen (s) + left) {
931 strcpy (&buf [rv], s);
932 rv += strlen (&buf [rv]);
936 rv += print_subexpression
937 (expr -> data.ns_add.rrname,
938 buf + rv, len - rv - left);
941 rv += print_subexpression
942 (expr -> data.ns_add.rrdata,
943 buf + rv, len - rv - left);
946 rv += print_subexpression
947 (expr -> data.ns_add.ttl,
948 buf + rv, len - rv - left);
957 strcpy (buf, "(null)");
962 rv = 12 + strlen (expr -> data.funcall.name);
964 strcpy (buf, "(funcall ");
965 strcpy (buf + 9, expr -> data.funcall.name);
967 rv += print_subexpression
968 (expr -> data.funcall.arglist, buf + rv,
977 rv = print_subexpression (expr -> data.arg.val, buf, len);
978 if (expr -> data.arg.next && rv + 2 < len) {
980 rv += print_subexpression (expr -> data.arg.next,
990 struct string_list *foo;
991 strcpy (buf, "(function");
992 for (foo = expr -> data.func -> args;
993 foo; foo = foo -> next) {
994 if (len > rv + 2 + strlen (foo -> string)) {
996 strcpy (&buf [rv], foo -> string);
997 rv += strlen (foo -> string);
1008 void print_expression (name, expr)
1010 struct expression *expr;
1014 print_subexpression (expr, buf, sizeof buf);
1015 log_info ("%s: %s", name, buf);
1018 int token_print_indent_concat (FILE *file, int col, int indent,
1020 const char *suffix, ...)
1027 va_start (list, suffix);
1028 s = va_arg (list, char *);
1032 s = va_arg (list, char *);
1036 t = dmalloc (len + 1, MDL);
1038 log_fatal ("token_print_indent: no memory for copy buffer");
1040 va_start (list, suffix);
1041 s = va_arg (list, char *);
1050 len = token_print_indent (file, col, indent,
1056 int token_indent_data_string (FILE *file, int col, int indent,
1057 const char *prefix, const char *suffix,
1058 struct data_string *data)
1064 /* See if this is just ASCII. */
1065 for (i = 0; i < data -> len; i++)
1066 if (!isascii (data -> data [i]) ||
1067 !isprint (data -> data [i]))
1070 /* If we have a purely ASCII string, output it as text. */
1071 if (i == data -> len) {
1072 char *buf = dmalloc (data -> len + 3, MDL);
1075 memcpy (buf + 1, data -> data, data -> len);
1076 buf [data -> len + 1] = '"';
1077 buf [data -> len + 2] = 0;
1078 i = token_print_indent (file, col, indent,
1079 prefix, suffix, buf);
1085 for (i = 0; i < data -> len; i++) {
1086 sprintf (obuf, "%2.2x", data -> data [i]);
1087 col = token_print_indent (file, col, indent,
1088 i == 0 ? prefix : "",
1089 (i + 1 == data -> len
1092 if (i + 1 != data -> len)
1093 col = token_print_indent (file, col, indent,
1094 prefix, suffix, ":");
1099 int token_print_indent (FILE *file, int col, int indent,
1101 const char *suffix, const char *buf)
1103 int len = strlen (buf) + strlen (prefix);
1104 if (col + len > 79) {
1105 if (indent + len < 79) {
1106 indent_spaces (file, indent);
1109 indent_spaces (file, col);
1110 col = len > 79 ? 0 : 79 - len - 1;
1112 } else if (prefix && *prefix) {
1113 fputs (prefix, file);
1114 col += strlen (prefix);
1118 if (suffix && *suffix) {
1119 if (col + strlen (suffix) > 79) {
1120 indent_spaces (file, indent);
1123 fputs (suffix, file);
1124 col += strlen (suffix);
1130 void indent_spaces (FILE *file, int indent)
1134 for (i = 0; i < indent; i++)
1138 #if defined (NSUPDATE)
1139 void print_dns_status (int status, ns_updque *uq)
1142 char *s = &obuf [0], *end = &obuf [1022];
1146 const char *predicate = "if", *en, *op;
1149 for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) {
1152 switch (u -> r_opcode)
1155 op = "rrset doesn't exist";
1159 op = "rrset exists";
1163 op = "domain doesn't exist";
1167 op = "domain exists";
1185 if (s != &obuf [0] && s + 1 < end)
1187 if (s + strlen (op) < end) {
1192 if (s != &obuf [0] && s + 1 < end)
1194 if (s + strlen (predicate) < end) {
1195 strcpy (s, predicate);
1203 if (s + strlen (u -> r_dname) < end) {
1204 strcpy (s, u -> r_dname);
1211 /* 27 is as big as a ttl can get. */
1214 (unsigned long)(u -> r_ttl));
1218 switch (u -> r_class) {
1232 if (s + strlen (en) < end) {
1238 switch (u -> r_type) {
1258 if (s + strlen (en) < end) {
1267 if (u -> r_type == T_TXT) {
1271 if (s + u -> r_size < end) {
1272 memcpy (s, u -> r_data, u -> r_size);
1274 if (u -> r_type == T_TXT) {
1283 if (s + strlen (op) < end) {
1288 if (u == ISC_LIST_TAIL (*uq))
1291 if (s == &obuf [0]) {
1292 strcpy (s, "empty update");
1295 if (status == NOERROR)
1299 en = isc_result_totext (status);
1303 en = "resolver failed";
1307 en = "format error";
1316 en = "not authorized";
1320 en = "not implemented";
1324 en = "not a single valid zone";
1328 en = "no such domain";
1332 en = "no such record";
1340 en = "server failed";
1344 en = "domain exists";
1348 en = "record exists";
1352 en = "unknown error";
1361 if (s + strlen (en) < end) {
1369 log_error ("%s", obuf);
1371 log_info ("%s", obuf);
1373 #endif /* NSUPDATE */