1: /* print.c
2:
3: Turn data structures into printable text. */
4:
5: /*
6: * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8: * Copyright (c) 1995-2003 by Internet Software Consortium
9: *
10: * Permission to use, copy, modify, and distribute this software for any
11: * purpose with or without fee is hereby granted, provided that the above
12: * copyright notice and this permission notice appear in all copies.
13: *
14: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21: *
22: * Internet Systems Consortium, Inc.
23: * 950 Charter Street
24: * Redwood City, CA 94063
25: * <info@isc.org>
26: * https://www.isc.org/
27: *
28: * This software has been written for Internet Systems Consortium
29: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30: * To learn more about Internet Systems Consortium, see
31: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33: * ``http://www.nominum.com''.
34: */
35:
36: #include "dhcpd.h"
37:
38: int db_time_format = DEFAULT_TIME_FORMAT;
39:
40: char *quotify_string (const char *s, const char *file, int line)
41: {
42: unsigned len = 0;
43: const char *sp;
44: char *buf, *nsp;
45:
46: for (sp = s; sp && *sp; sp++) {
47: if (*sp == ' ')
48: len++;
49: else if (!isascii ((int)*sp) || !isprint ((int)*sp))
50: len += 4;
51: else if (*sp == '"' || *sp == '\\')
52: len += 2;
53: else
54: len++;
55: }
56:
57: buf = dmalloc (len + 1, file, line);
58: if (buf) {
59: nsp = buf;
60: for (sp = s; sp && *sp; sp++) {
61: if (*sp == ' ')
62: *nsp++ = ' ';
63: else if (!isascii ((int)*sp) || !isprint ((int)*sp)) {
64: sprintf (nsp, "\\%03o",
65: *(const unsigned char *)sp);
66: nsp += 4;
67: } else if (*sp == '"' || *sp == '\\') {
68: *nsp++ = '\\';
69: *nsp++ = *sp;
70: } else
71: *nsp++ = *sp;
72: }
73: *nsp++ = 0;
74: }
75: return buf;
76: }
77:
78: char *quotify_buf (const unsigned char *s, unsigned len,
79: const char *file, int line)
80: {
81: unsigned nulen = 0;
82: char *buf, *nsp;
83: int i;
84:
85: for (i = 0; i < len; i++) {
86: if (s [i] == ' ')
87: nulen++;
88: else if (!isascii (s [i]) || !isprint (s [i]))
89: nulen += 4;
90: else if (s [i] == '"' || s [i] == '\\')
91: nulen += 2;
92: else
93: nulen++;
94: }
95:
96: buf = dmalloc (nulen + 1, MDL);
97: if (buf) {
98: nsp = buf;
99: for (i = 0; i < len; i++) {
100: if (s [i] == ' ')
101: *nsp++ = ' ';
102: else if (!isascii (s [i]) || !isprint (s [i])) {
103: sprintf (nsp, "\\%03o", s [i]);
104: nsp += 4;
105: } else if (s [i] == '"' || s [i] == '\\') {
106: *nsp++ = '\\';
107: *nsp++ = s [i];
108: } else
109: *nsp++ = s [i];
110: }
111: *nsp++ = 0;
112: }
113: return buf;
114: }
115:
116: char *print_base64 (const unsigned char *buf, unsigned len,
117: const char *file, int line)
118: {
119: char *s, *b;
120: unsigned bl;
121: int i;
122: unsigned val, extra;
123: static char to64 [] =
124: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
125:
126: bl = ((len * 4 + 2) / 3) + 1;
127: b = dmalloc (bl + 1, file, line);
128: if (!b)
129: return (char *)0;
130:
131: i = 0;
132: s = b;
133: while (i != len) {
134: val = buf [i++];
135: extra = val & 3;
136: val = val >> 2;
137: *s++ = to64 [val];
138: if (i == len) {
139: *s++ = to64 [extra << 4];
140: *s++ = '=';
141: break;
142: }
143: val = (extra << 8) + buf [i++];
144: extra = val & 15;
145: val = val >> 4;
146: *s++ = to64 [val];
147: if (i == len) {
148: *s++ = to64 [extra << 2];
149: *s++ = '=';
150: break;
151: }
152: val = (extra << 8) + buf [i++];
153: extra = val & 0x3f;
154: val = val >> 6;
155: *s++ = to64 [val];
156: *s++ = to64 [extra];
157: }
158: if (!len)
159: *s++ = '=';
160: *s++ = 0;
161: if (s > b + bl + 1)
162: abort ();
163: return b;
164: }
165:
166: char *print_hw_addr (htype, hlen, data)
167: int htype;
168: int hlen;
169: unsigned char *data;
170: {
171: static char habuf [49];
172: char *s;
173: int i;
174:
175: if (hlen <= 0)
176: habuf [0] = 0;
177: else {
178: s = habuf;
179: for (i = 0; i < hlen; i++) {
180: sprintf (s, "%02x", data [i]);
181: s += strlen (s);
182: *s++ = ':';
183: }
184: *--s = 0;
185: }
186: return habuf;
187: }
188:
189: void print_lease (lease)
190: struct lease *lease;
191: {
192: struct tm *t;
193: char tbuf [32];
194:
195: log_debug (" Lease %s",
196: piaddr (lease -> ip_addr));
197:
198: t = gmtime (&lease -> starts);
199: strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
200: log_debug (" start %s", tbuf);
201:
202: t = gmtime (&lease -> ends);
203: strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
204: log_debug (" end %s", tbuf);
205:
206: if (lease -> hardware_addr.hlen)
207: log_debug (" hardware addr = %s",
208: print_hw_addr (lease -> hardware_addr.hbuf [0],
209: lease -> hardware_addr.hlen - 1,
210: &lease -> hardware_addr.hbuf [1]));
211: log_debug (" host %s ",
212: lease -> host ? lease -> host -> name : "<none>");
213: }
214:
215: #if defined (DEBUG_PACKET)
216: void dump_packet_option (struct option_cache *oc,
217: struct packet *packet,
218: struct lease *lease,
219: struct client_state *client,
220: struct option_state *in_options,
221: struct option_state *cfg_options,
222: struct binding_scope **scope,
223: struct universe *u, void *foo)
224: {
225: const char *name, *dot;
226: struct data_string ds;
227: memset (&ds, 0, sizeof ds);
228:
229: if (u != &dhcp_universe) {
230: name = u -> name;
231: dot = ".";
232: } else {
233: name = "";
234: dot = "";
235: }
236: if (evaluate_option_cache (&ds, packet, lease, client,
237: in_options, cfg_options, scope, oc, MDL)) {
238: log_debug (" option %s%s%s %s;\n",
239: name, dot, oc -> option -> name,
240: pretty_print_option (oc -> option,
241: ds.data, ds.len, 1, 1));
242: data_string_forget (&ds, MDL);
243: }
244: }
245:
246: void dump_packet (tp)
247: struct packet *tp;
248: {
249: struct dhcp_packet *tdp = tp -> raw;
250:
251: log_debug ("packet length %d", tp -> packet_length);
252: log_debug ("op = %d htype = %d hlen = %d hops = %d",
253: tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
254: log_debug ("xid = %x secs = %ld flags = %x",
255: tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
256: log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
257: log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
258: log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
259: log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
260: log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
261: ((unsigned char *)(tdp -> chaddr)) [0],
262: ((unsigned char *)(tdp -> chaddr)) [1],
263: ((unsigned char *)(tdp -> chaddr)) [2],
264: ((unsigned char *)(tdp -> chaddr)) [3],
265: ((unsigned char *)(tdp -> chaddr)) [4],
266: ((unsigned char *)(tdp -> chaddr)) [5]);
267: log_debug ("filename = %s", tdp -> file);
268: log_debug ("server_name = %s", tdp -> sname);
269: if (tp -> options_valid) {
270: int i;
271:
272: for (i = 0; i < tp -> options -> universe_count; i++) {
273: if (tp -> options -> universes [i]) {
274: option_space_foreach (tp, (struct lease *)0,
275: (struct client_state *)0,
276: (struct option_state *)0,
277: tp -> options,
278: &global_scope,
279: universes [i], 0,
280: dump_packet_option);
281: }
282: }
283: }
284: log_debug ("%s", "");
285: }
286: #endif
287:
288: void dump_raw (buf, len)
289: const unsigned char *buf;
290: unsigned len;
291: {
292: int i;
293: char lbuf [80];
294: int lbix = 0;
295:
296: /*
297: 1 2 3 4 5 6 7
298: 01234567890123456789012345678901234567890123456789012345678901234567890123
299: 280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................
300: */
301:
302: memset(lbuf, ' ', 79);
303: lbuf [79] = 0;
304:
305: for (i = 0; i < len; i++) {
306: if ((i & 15) == 0) {
307: if (lbix) {
308: lbuf[53]=' ';
309: lbuf[54]=' ';
310: lbuf[55]=' ';
311: lbuf[73]='\0';
312: log_info ("%s", lbuf);
313: }
314: memset(lbuf, ' ', 79);
315: lbuf [79] = 0;
316: sprintf (lbuf, "%03x:", i);
317: lbix = 4;
318: } else if ((i & 7) == 0)
319: lbuf [lbix++] = ' ';
320:
321: if(isprint(buf[i])) {
322: lbuf[56+(i%16)]=buf[i];
323: } else {
324: lbuf[56+(i%16)]='.';
325: }
326:
327: sprintf (&lbuf [lbix], " %02x", buf [i]);
328: lbix += 3;
329: lbuf[lbix]=' ';
330:
331: }
332: lbuf[53]=' ';
333: lbuf[54]=' ';
334: lbuf[55]=' ';
335: lbuf[73]='\0';
336: log_info ("%s", lbuf);
337: }
338:
339: void hash_dump (table)
340: struct hash_table *table;
341: {
342: int i;
343: struct hash_bucket *bp;
344:
345: if (!table)
346: return;
347:
348: for (i = 0; i < table -> hash_count; i++) {
349: if (!table -> buckets [i])
350: continue;
351: log_info ("hash bucket %d:", i);
352: for (bp = table -> buckets [i]; bp; bp = bp -> next) {
353: if (bp -> len)
354: dump_raw (bp -> name, bp -> len);
355: else
356: log_info ("%s", (const char *)bp -> name);
357: }
358: }
359: }
360:
361: /*
362: * print a string as hex. This only outputs
363: * colon separated hex list no matter what
364: * the input looks like. See print_hex
365: * for a function that prints either cshl
366: * or a string if all bytes are printible
367: * It only uses limit characters from buf
368: * and doesn't do anything if buf == NULL
369: *
370: * len - length of data
371: * data - input data
372: * limit - length of buf to use
373: * buf - output buffer
374: */
375: void print_hex_only (len, data, limit, buf)
376: unsigned len;
377: const u_int8_t *data;
378: unsigned limit;
379: char *buf;
380: {
381: unsigned i;
382:
383: if ((buf == NULL) || (limit < 3))
384: return;
385:
386: for (i = 0; (i < limit / 3) && (i < len); i++) {
387: sprintf(&buf[i*3], "%02x:", data[i]);
388: }
389: buf[(i * 3) - 1] = 0;
390: return;
391: }
392:
393: /*
394: * print a string as either text if all the characters
395: * are printable or colon separated hex if they aren't
396: *
397: * len - length of data
398: * data - input data
399: * limit - length of buf to use
400: * buf - output buffer
401: */
402: void print_hex_or_string (len, data, limit, buf)
403: unsigned len;
404: const u_int8_t *data;
405: unsigned limit;
406: char *buf;
407: {
408: unsigned i;
409: if ((buf == NULL) || (limit < 3))
410: return;
411:
412: for (i = 0; (i < (limit - 3)) && (i < len); i++) {
413: if (!isascii(data[i]) || !isprint(data[i])) {
414: print_hex_only(len, data, limit, buf);
415: return;
416: }
417: }
418:
419: buf[0] = '"';
420: i = len;
421: if (i > (limit - 3))
422: i = limit - 3;
423: memcpy(&buf[1], data, i);
424: buf[i + 1] = '"';
425: buf[i + 2] = 0;
426: return;
427: }
428:
429: /*
430: * print a string as either hex or text
431: * using static buffers to hold the output
432: *
433: * len - length of data
434: * data - input data
435: * limit - length of buf
436: * buf_num - the output buffer to use
437: */
438: #define HBLEN 1024
439: char *print_hex(len, data, limit, buf_num)
440: unsigned len;
441: const u_int8_t *data;
442: unsigned limit;
443: unsigned buf_num;
444: {
445: static char hex_buf_1[HBLEN + 1];
446: static char hex_buf_2[HBLEN + 1];
447: static char hex_buf_3[HBLEN + 1];
448: char *hex_buf;
449:
450: switch(buf_num) {
451: case 0:
452: hex_buf = hex_buf_1;
453: if (limit >= sizeof(hex_buf_1))
454: limit = sizeof(hex_buf_1);
455: break;
456: case 1:
457: hex_buf = hex_buf_2;
458: if (limit >= sizeof(hex_buf_2))
459: limit = sizeof(hex_buf_2);
460: break;
461: case 2:
462: hex_buf = hex_buf_3;
463: if (limit >= sizeof(hex_buf_3))
464: limit = sizeof(hex_buf_3);
465: break;
466: default:
467: return(NULL);
468: }
469:
470: print_hex_or_string(len, data, limit, hex_buf);
471: return(hex_buf);
472: }
473:
474: #define DQLEN 80
475:
476: char *print_dotted_quads (len, data)
477: unsigned len;
478: const u_int8_t *data;
479: {
480: static char dq_buf [DQLEN + 1];
481: int i;
482: char *s, *last;
483:
484: s = &dq_buf [0];
485: last = s;
486:
487: i = 0;
488:
489: /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe%
490: * The sprintf can't exceed 18 bytes, and since the loop enforces
491: * 21 bytes of space per iteration at no time can we exit the
492: * loop without at least 3 bytes spare.
493: */
494: do {
495: sprintf (s, "%u.%u.%u.%u, ",
496: data [i], data [i + 1], data [i + 2], data [i + 3]);
497: s += strlen (s);
498: i += 4;
499: } while ((s - &dq_buf [0] > DQLEN - 21) &&
500: i + 3 < len);
501: if (i == len)
502: s [-2] = 0;
503: else
504: strcpy (s, "...");
505: return dq_buf;
506: }
507:
508: char *print_dec_1 (val)
509: unsigned long val;
510: {
511: static char vbuf [32];
512: sprintf (vbuf, "%lu", val);
513: return vbuf;
514: }
515:
516: char *print_dec_2 (val)
517: unsigned long val;
518: {
519: static char vbuf [32];
520: sprintf (vbuf, "%lu", val);
521: return vbuf;
522: }
523:
524: static unsigned print_subexpression (struct expression *, char *, unsigned);
525:
526: static unsigned print_subexpression (expr, buf, len)
527: struct expression *expr;
528: char *buf;
529: unsigned len;
530: {
531: unsigned rv, left;
532: const char *s;
533:
534: switch (expr -> op) {
535: case expr_none:
536: if (len > 3) {
537: strcpy (buf, "nil");
538: return 3;
539: }
540: break;
541:
542: case expr_match:
543: if (len > 7) {
544: strcpy (buf, "(match)");
545: return 7;
546: }
547: break;
548:
549: case expr_check:
550: rv = 10 + strlen (expr -> data.check -> name);
551: if (len > rv) {
552: sprintf (buf, "(check %s)",
553: expr -> data.check -> name);
554: return rv;
555: }
556: break;
557:
558: case expr_equal:
559: if (len > 6) {
560: rv = 4;
561: strcpy (buf, "(eq ");
562: rv += print_subexpression (expr -> data.equal [0],
563: buf + rv, len - rv - 2);
564: buf [rv++] = ' ';
565: rv += print_subexpression (expr -> data.equal [1],
566: buf + rv, len - rv - 1);
567: buf [rv++] = ')';
568: buf [rv] = 0;
569: return rv;
570: }
571: break;
572:
573: case expr_not_equal:
574: if (len > 7) {
575: rv = 5;
576: strcpy (buf, "(neq ");
577: rv += print_subexpression (expr -> data.equal [0],
578: buf + rv, len - rv - 2);
579: buf [rv++] = ' ';
580: rv += print_subexpression (expr -> data.equal [1],
581: buf + rv, len - rv - 1);
582: buf [rv++] = ')';
583: buf [rv] = 0;
584: return rv;
585: }
586: break;
587:
588: case expr_regex_match:
589: if (len > 10) {
590: rv = 4;
591: strcpy(buf, "(regex ");
592: rv += print_subexpression(expr->data.equal[0],
593: buf + rv, len - rv - 2);
594: buf[rv++] = ' ';
595: rv += print_subexpression(expr->data.equal[1],
596: buf + rv, len - rv - 1);
597: buf[rv++] = ')';
598: buf[rv] = 0;
599: return rv;
600: }
601: break;
602:
603: case expr_substring:
604: if (len > 11) {
605: rv = 8;
606: strcpy (buf, "(substr ");
607: rv += print_subexpression (expr -> data.substring.expr,
608: buf + rv, len - rv - 3);
609: buf [rv++] = ' ';
610: rv += print_subexpression
611: (expr -> data.substring.offset,
612: buf + rv, len - rv - 2);
613: buf [rv++] = ' ';
614: rv += print_subexpression (expr -> data.substring.len,
615: buf + rv, len - rv - 1);
616: buf [rv++] = ')';
617: buf [rv] = 0;
618: return rv;
619: }
620: break;
621:
622: case expr_suffix:
623: if (len > 10) {
624: rv = 8;
625: strcpy (buf, "(suffix ");
626: rv += print_subexpression (expr -> data.suffix.expr,
627: buf + rv, len - rv - 2);
628: if (len > rv)
629: buf [rv++] = ' ';
630: rv += print_subexpression (expr -> data.suffix.len,
631: buf + rv, len - rv - 1);
632: if (len > rv)
633: buf [rv++] = ')';
634: buf [rv] = 0;
635: return rv;
636: }
637: break;
638:
639: case expr_lcase:
640: if (len > 9) {
641: rv = 7;
642: strcpy(buf, "(lcase ");
643: rv += print_subexpression(expr->data.lcase,
644: buf + rv, len - rv - 1);
645: buf[rv++] = ')';
646: buf[rv] = 0;
647: return rv;
648: }
649: break;
650:
651: case expr_ucase:
652: if (len > 9) {
653: rv = 7;
654: strcpy(buf, "(ucase ");
655: rv += print_subexpression(expr->data.ucase,
656: buf + rv, len - rv - 1);
657: buf[rv++] = ')';
658: buf[rv] = 0;
659: return rv;
660: }
661: break;
662:
663: case expr_concat:
664: if (len > 10) {
665: rv = 8;
666: strcpy (buf, "(concat ");
667: rv += print_subexpression (expr -> data.concat [0],
668: buf + rv, len - rv - 2);
669: buf [rv++] = ' ';
670: rv += print_subexpression (expr -> data.concat [1],
671: buf + rv, len - rv - 1);
672: buf [rv++] = ')';
673: buf [rv] = 0;
674: return rv;
675: }
676: break;
677:
678: case expr_pick_first_value:
679: if (len > 8) {
680: rv = 6;
681: strcpy (buf, "(pick1st ");
682: rv += print_subexpression
683: (expr -> data.pick_first_value.car,
684: buf + rv, len - rv - 2);
685: buf [rv++] = ' ';
686: rv += print_subexpression
687: (expr -> data.pick_first_value.cdr,
688: buf + rv, len - rv - 1);
689: buf [rv++] = ')';
690: buf [rv] = 0;
691: return rv;
692: }
693: break;
694:
695: case expr_host_lookup:
696: rv = 15 + strlen (expr -> data.host_lookup -> hostname);
697: if (len > rv) {
698: sprintf (buf, "(dns-lookup %s)",
699: expr -> data.host_lookup -> hostname);
700: return rv;
701: }
702: break;
703:
704: case expr_and:
705: s = "and";
706: binop:
707: rv = strlen (s);
708: if (len > rv + 4) {
709: buf [0] = '(';
710: strcpy (&buf [1], s);
711: rv += 1;
712: buf [rv++] = ' ';
713: rv += print_subexpression (expr -> data.and [0],
714: buf + rv, len - rv - 2);
715: buf [rv++] = ' ';
716: rv += print_subexpression (expr -> data.and [1],
717: buf + rv, len - rv - 1);
718: buf [rv++] = ')';
719: buf [rv] = 0;
720: return rv;
721: }
722: break;
723:
724: case expr_or:
725: s = "or";
726: goto binop;
727:
728: case expr_add:
729: s = "+";
730: goto binop;
731:
732: case expr_subtract:
733: s = "-";
734: goto binop;
735:
736: case expr_multiply:
737: s = "*";
738: goto binop;
739:
740: case expr_divide:
741: s = "/";
742: goto binop;
743:
744: case expr_remainder:
745: s = "%";
746: goto binop;
747:
748: case expr_binary_and:
749: s = "&";
750: goto binop;
751:
752: case expr_binary_or:
753: s = "|";
754: goto binop;
755:
756: case expr_binary_xor:
757: s = "^";
758: goto binop;
759:
760: case expr_not:
761: if (len > 6) {
762: rv = 5;
763: strcpy (buf, "(not ");
764: rv += print_subexpression (expr -> data.not,
765: buf + rv, len - rv - 1);
766: buf [rv++] = ')';
767: buf [rv] = 0;
768: return rv;
769: }
770: break;
771:
772: case expr_config_option:
773: s = "cfg-option";
774: goto dooption;
775:
776: case expr_option:
777: s = "option";
778: dooption:
779: rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
780: strlen (expr -> data.option -> universe -> name));
781: if (len > rv) {
782: sprintf (buf, "(option %s.%s)",
783: expr -> data.option -> universe -> name,
784: expr -> data.option -> name);
785: return rv;
786: }
787: break;
788:
789: case expr_hardware:
790: if (len > 10) {
791: strcpy (buf, "(hardware)");
792: return 10;
793: }
794: break;
795:
796: case expr_packet:
797: if (len > 10) {
798: rv = 8;
799: strcpy (buf, "(substr ");
800: rv += print_subexpression (expr -> data.packet.offset,
801: buf + rv, len - rv - 2);
802: buf [rv++] = ' ';
803: rv += print_subexpression (expr -> data.packet.len,
804: buf + rv, len - rv - 1);
805: buf [rv++] = ')';
806: buf [rv] = 0;
807: return rv;
808: }
809: break;
810:
811: case expr_const_data:
812: s = print_hex_1 (expr -> data.const_data.len,
813: expr -> data.const_data.data, len);
814: rv = strlen (s);
815: if (rv >= len)
816: rv = len - 1;
817: strncpy (buf, s, rv);
818: buf [rv] = 0;
819: return rv;
820:
821: case expr_encapsulate:
822: rv = 13;
823: strcpy (buf, "(encapsulate ");
824: rv += expr -> data.encapsulate.len;
825: if (rv + 2 > len)
826: rv = len - 2;
827: strncpy (buf,
828: (const char *)expr -> data.encapsulate.data, rv - 13);
829: buf [rv++] = ')';
830: buf [rv++] = 0;
831: break;
832:
833: case expr_extract_int8:
834: if (len > 7) {
835: rv = 6;
836: strcpy (buf, "(int8 ");
837: rv += print_subexpression (expr -> data.extract_int,
838: buf + rv, len - rv - 1);
839: buf [rv++] = ')';
840: buf [rv] = 0;
841: return rv;
842: }
843: break;
844:
845: case expr_extract_int16:
846: if (len > 8) {
847: rv = 7;
848: strcpy (buf, "(int16 ");
849: rv += print_subexpression (expr -> data.extract_int,
850: buf + rv, len - rv - 1);
851: buf [rv++] = ')';
852: buf [rv] = 0;
853: return rv;
854: }
855: break;
856:
857: case expr_extract_int32:
858: if (len > 8) {
859: rv = 7;
860: strcpy (buf, "(int32 ");
861: rv += print_subexpression (expr -> data.extract_int,
862: buf + rv, len - rv - 1);
863: buf [rv++] = ')';
864: buf [rv] = 0;
865: return rv;
866: }
867: break;
868:
869: case expr_encode_int8:
870: if (len > 7) {
871: rv = 6;
872: strcpy (buf, "(to-int8 ");
873: rv += print_subexpression (expr -> data.encode_int,
874: buf + rv, len - rv - 1);
875: buf [rv++] = ')';
876: buf [rv] = 0;
877: return rv;
878: }
879: break;
880:
881: case expr_encode_int16:
882: if (len > 8) {
883: rv = 7;
884: strcpy (buf, "(to-int16 ");
885: rv += print_subexpression (expr -> data.encode_int,
886: buf + rv, len - rv - 1);
887: buf [rv++] = ')';
888: buf [rv] = 0;
889: return rv;
890: }
891: break;
892:
893: case expr_encode_int32:
894: if (len > 8) {
895: rv = 7;
896: strcpy (buf, "(to-int32 ");
897: rv += print_subexpression (expr -> data.encode_int,
898: buf + rv, len - rv - 1);
899: buf [rv++] = ')';
900: buf [rv] = 0;
901: return rv;
902: }
903: break;
904:
905: case expr_const_int:
906: s = print_dec_1 (expr -> data.const_int);
907: rv = strlen (s);
908: if (len > rv) {
909: strcpy (buf, s);
910: return rv;
911: }
912: break;
913:
914: case expr_exists:
915: rv = 10 + (strlen (expr -> data.option -> name) +
916: strlen (expr -> data.option -> universe -> name));
917: if (len > rv) {
918: sprintf (buf, "(exists %s.%s)",
919: expr -> data.option -> universe -> name,
920: expr -> data.option -> name);
921: return rv;
922: }
923: break;
924:
925: case expr_variable_exists:
926: rv = 10 + strlen (expr -> data.variable);
927: if (len > rv) {
928: sprintf (buf, "(defined %s)", expr -> data.variable);
929: return rv;
930: }
931: break;
932:
933: case expr_variable_reference:
934: rv = strlen (expr -> data.variable);
935: if (len > rv) {
936: sprintf (buf, "%s", expr -> data.variable);
937: return rv;
938: }
939: break;
940:
941: case expr_known:
942: s = "known";
943: astring:
944: rv = strlen (s);
945: if (len > rv) {
946: strcpy (buf, s);
947: return rv;
948: }
949: break;
950:
951: case expr_leased_address:
952: s = "leased-address";
953: goto astring;
954:
955: case expr_client_state:
956: s = "client-state";
957: goto astring;
958:
959: case expr_host_decl_name:
960: s = "host-decl-name";
961: goto astring;
962:
963: case expr_lease_time:
964: s = "lease-time";
965: goto astring;
966:
967: case expr_static:
968: s = "static";
969: goto astring;
970:
971: case expr_filename:
972: s = "filename";
973: goto astring;
974:
975: case expr_sname:
976: s = "server-name";
977: goto astring;
978:
979: case expr_reverse:
980: if (len > 11) {
981: rv = 13;
982: strcpy (buf, "(reverse ");
983: rv += print_subexpression (expr -> data.reverse.width,
984: buf + rv, len - rv - 2);
985: buf [rv++] = ' ';
986: rv += print_subexpression (expr -> data.reverse.buffer,
987: buf + rv, len - rv - 1);
988: buf [rv++] = ')';
989: buf [rv] = 0;
990: return rv;
991: }
992: break;
993:
994: case expr_binary_to_ascii:
995: if (len > 5) {
996: rv = 9;
997: strcpy (buf, "(b2a ");
998: rv += print_subexpression (expr -> data.b2a.base,
999: buf + rv, len - rv - 4);
1000: buf [rv++] = ' ';
1001: rv += print_subexpression (expr -> data.b2a.width,
1002: buf + rv, len - rv - 3);
1003: buf [rv++] = ' ';
1004: rv += print_subexpression (expr -> data.b2a.separator,
1005: buf + rv, len - rv - 2);
1006: buf [rv++] = ' ';
1007: rv += print_subexpression (expr -> data.b2a.buffer,
1008: buf + rv, len - rv - 1);
1009: buf [rv++] = ')';
1010: buf [rv] = 0;
1011: return rv;
1012: }
1013: break;
1014:
1015: case expr_dns_transaction:
1016: rv = 10;
1017: if (len < rv + 2) {
1018: buf [0] = '(';
1019: strcpy (&buf [1], "ns-update ");
1020: while (len < rv + 2) {
1021: rv += print_subexpression
1022: (expr -> data.dns_transaction.car,
1023: buf + rv, len - rv - 2);
1024: buf [rv++] = ' ';
1025: expr = expr -> data.dns_transaction.cdr;
1026: }
1027: buf [rv - 1] = ')';
1028: buf [rv] = 0;
1029: return rv;
1030: }
1031: return 0;
1032:
1033: case expr_ns_delete:
1034: s = "delete";
1035: left = 4;
1036: goto dodnsupd;
1037: case expr_ns_exists:
1038: s = "exists";
1039: left = 4;
1040: goto dodnsupd;
1041: case expr_ns_not_exists:
1042: s = "not_exists";
1043: left = 4;
1044: goto dodnsupd;
1045: case expr_ns_add:
1046: s = "update";
1047: left = 5;
1048: dodnsupd:
1049: rv = strlen (s);
1050: if (len > strlen (s) + 1) {
1051: buf [0] = '(';
1052: strcpy (buf + 1, s);
1053: rv++;
1054: buf [rv++] = ' ';
1055: s = print_dec_1 (expr -> data.ns_add.rrclass);
1056: if (len > rv + strlen (s) + left) {
1057: strcpy (&buf [rv], s);
1058: rv += strlen (&buf [rv]);
1059: }
1060: buf [rv++] = ' ';
1061: left--;
1062: s = print_dec_1 (expr -> data.ns_add.rrtype);
1063: if (len > rv + strlen (s) + left) {
1064: strcpy (&buf [rv], s);
1065: rv += strlen (&buf [rv]);
1066: }
1067: buf [rv++] = ' ';
1068: left--;
1069: rv += print_subexpression
1070: (expr -> data.ns_add.rrname,
1071: buf + rv, len - rv - left);
1072: buf [rv++] = ' ';
1073: left--;
1074: rv += print_subexpression
1075: (expr -> data.ns_add.rrdata,
1076: buf + rv, len - rv - left);
1077: buf [rv++] = ' ';
1078: left--;
1079: rv += print_subexpression
1080: (expr -> data.ns_add.ttl,
1081: buf + rv, len - rv - left);
1082: buf [rv++] = ')';
1083: buf [rv] = 0;
1084: return rv;
1085: }
1086: break;
1087:
1088: case expr_null:
1089: if (len > 6) {
1090: strcpy (buf, "(null)");
1091: return 6;
1092: }
1093: break;
1094: case expr_funcall:
1095: rv = 12 + strlen (expr -> data.funcall.name);
1096: if (len > rv + 1) {
1097: strcpy (buf, "(funcall ");
1098: strcpy (buf + 9, expr -> data.funcall.name);
1099: buf [rv++] = ' ';
1100: rv += print_subexpression
1101: (expr -> data.funcall.arglist, buf + rv,
1102: len - rv - 1);
1103: buf [rv++] = ')';
1104: buf [rv] = 0;
1105: return rv;
1106: }
1107: break;
1108:
1109: case expr_arg:
1110: rv = print_subexpression (expr -> data.arg.val, buf, len);
1111: if (expr -> data.arg.next && rv + 2 < len) {
1112: buf [rv++] = ' ';
1113: rv += print_subexpression (expr -> data.arg.next,
1114: buf, len);
1115: if (rv + 1 < len)
1116: buf [rv++] = 0;
1117: return rv;
1118: }
1119: break;
1120:
1121: case expr_function:
1122: rv = 9;
1123: if (len > rv + 1) {
1124: struct string_list *foo;
1125: strcpy (buf, "(function");
1126: for (foo = expr -> data.func -> args;
1127: foo; foo = foo -> next) {
1128: if (len > rv + 2 + strlen (foo -> string)) {
1129: buf [rv - 1] = ' ';
1130: strcpy (&buf [rv], foo -> string);
1131: rv += strlen (foo -> string);
1132: }
1133: }
1134: buf [rv++] = ')';
1135: buf [rv] = 0;
1136: return rv;
1137: }
1138:
1139: default:
1140: log_fatal("Impossible case at %s:%d (undefined expression "
1141: "%d).", MDL, expr->op);
1142: break;
1143: }
1144: return 0;
1145: }
1146:
1147: void print_expression (name, expr)
1148: const char *name;
1149: struct expression *expr;
1150: {
1151: char buf [1024];
1152:
1153: print_subexpression (expr, buf, sizeof buf);
1154: log_info ("%s: %s", name, buf);
1155: }
1156:
1157: int token_print_indent_concat (FILE *file, int col, int indent,
1158: const char *prefix,
1159: const char *suffix, ...)
1160: {
1161: va_list list;
1162: unsigned len;
1163: char *s, *t, *u;
1164:
1165: va_start (list, suffix);
1166: s = va_arg (list, char *);
1167: len = 0;
1168: while (s) {
1169: len += strlen (s);
1170: s = va_arg (list, char *);
1171: }
1172: va_end (list);
1173:
1174: t = dmalloc (len + 1, MDL);
1175: if (!t)
1176: log_fatal ("token_print_indent: no memory for copy buffer");
1177:
1178: va_start (list, suffix);
1179: s = va_arg (list, char *);
1180: u = t;
1181: while (s) {
1182: len = strlen (s);
1183: strcpy (u, s);
1184: u += len;
1185: s = va_arg (list, char *);
1186: }
1187: va_end (list);
1188:
1189: len = token_print_indent (file, col, indent,
1190: prefix, suffix, t);
1191: dfree (t, MDL);
1192: return col;
1193: }
1194:
1195: int token_indent_data_string (FILE *file, int col, int indent,
1196: const char *prefix, const char *suffix,
1197: struct data_string *data)
1198: {
1199: int i;
1200: char *buf;
1201: char obuf [3];
1202:
1203: /* See if this is just ASCII. */
1204: for (i = 0; i < data -> len; i++)
1205: if (!isascii (data -> data [i]) ||
1206: !isprint (data -> data [i]))
1207: break;
1208:
1209: /* If we have a purely ASCII string, output it as text. */
1210: if (i == data -> len) {
1211: buf = dmalloc (data -> len + 3, MDL);
1212: if (buf) {
1213: buf [0] = '"';
1214: memcpy (buf + 1, data -> data, data -> len);
1215: buf [data -> len + 1] = '"';
1216: buf [data -> len + 2] = 0;
1217: i = token_print_indent (file, col, indent,
1218: prefix, suffix, buf);
1219: dfree (buf, MDL);
1220: return i;
1221: }
1222: }
1223:
1224: for (i = 0; i < data -> len; i++) {
1225: sprintf (obuf, "%2.2x", data -> data [i]);
1226: col = token_print_indent (file, col, indent,
1227: i == 0 ? prefix : "",
1228: (i + 1 == data -> len
1229: ? suffix
1230: : ""), obuf);
1231: if (i + 1 != data -> len)
1232: col = token_print_indent (file, col, indent,
1233: prefix, suffix, ":");
1234: }
1235: return col;
1236: }
1237:
1238: int token_print_indent (FILE *file, int col, int indent,
1239: const char *prefix,
1240: const char *suffix, const char *buf)
1241: {
1242: int len = strlen (buf) + strlen (prefix);
1243: if (col + len > 79) {
1244: if (indent + len < 79) {
1245: indent_spaces (file, indent);
1246: col = indent;
1247: } else {
1248: indent_spaces (file, col);
1249: col = len > 79 ? 0 : 79 - len - 1;
1250: }
1251: } else if (prefix && *prefix) {
1252: fputs (prefix, file);
1253: col += strlen (prefix);
1254: }
1255: fputs (buf, file);
1256: col += len;
1257: if (suffix && *suffix) {
1258: if (col + strlen (suffix) > 79) {
1259: indent_spaces (file, indent);
1260: col = indent;
1261: } else {
1262: fputs (suffix, file);
1263: col += strlen (suffix);
1264: }
1265: }
1266: return col;
1267: }
1268:
1269: void indent_spaces (FILE *file, int indent)
1270: {
1271: int i;
1272: fputc ('\n', file);
1273: for (i = 0; i < indent; i++)
1274: fputc (' ', file);
1275: }
1276:
1277: #if defined (NSUPDATE)
1278: void print_dns_status (int status, ns_updque *uq)
1279: {
1280: char obuf [1024];
1281: char *s = &obuf [0], *end = &obuf [1022];
1282: ns_updrec *u;
1283: int position;
1284: int ttlp;
1285: const char *predicate = "if", *en, *op;
1286: int errorp;
1287:
1288: for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) {
1289: ttlp = 0;
1290:
1291: switch (u -> r_opcode)
1292: {
1293: case NXRRSET:
1294: op = "rrset doesn't exist";
1295: position = 1;
1296: break;
1297: case YXRRSET:
1298: op = "rrset exists";
1299: position = 1;
1300: break;
1301: case NXDOMAIN:
1302: op = "domain doesn't exist";
1303: position = 1;
1304: break;
1305: case YXDOMAIN:
1306: op = "domain exists";
1307: position = 1;
1308: break;
1309: case ADD:
1310: op = "add";
1311: position = 0;
1312: ttlp = 1;
1313: break;
1314: case DELETE:
1315: op = "delete";
1316: position = 0;
1317: break;
1318: default:
1319: op = "unknown";
1320: position = 0;
1321: break;
1322: }
1323: if (!position) {
1324: if (s != &obuf [0] && s + 1 < end)
1325: *s++ = ' ';
1326: if (s + strlen (op) < end) {
1327: strcpy (s, op);
1328: s += strlen (s);
1329: }
1330: } else {
1331: if (s != &obuf [0] && s + 1 < end)
1332: *s++ = ' ';
1333: if (s + strlen (predicate) < end) {
1334: strcpy (s, predicate);
1335: s += strlen (s);
1336: }
1337: predicate = "and";
1338: }
1339: if (u -> r_dname) {
1340: if (s + 1 < end)
1341: *s++ = ' ';
1342: if (s + strlen (u -> r_dname) < end) {
1343: strcpy (s, u -> r_dname);
1344: s += strlen (s);
1345: }
1346: }
1347: if (ttlp) {
1348: if (s + 1 < end)
1349: *s++ = ' ';
1350: /* 27 is as big as a ttl can get. */
1351: if (s + 27 < end) {
1352: sprintf (s, "%lu",
1353: (unsigned long)(u -> r_ttl));
1354: s += strlen (s);
1355: }
1356: }
1357: switch (u -> r_class) {
1358: case C_IN:
1359: en = "IN";
1360: break;
1361: case C_CHAOS:
1362: en = "CHAOS";
1363: break;
1364: case C_HS:
1365: en = "HS";
1366: break;
1367: default:
1368: en = "UNKNOWN";
1369: break;
1370: }
1371: if (s + strlen (en) < end) {
1372: if (s + 1 < end)
1373: *s++ = ' ';
1374: strcpy (s, en);
1375: s += strlen (en);
1376: }
1377: switch (u -> r_type) {
1378: case T_A:
1379: en = "A";
1380: break;
1381: case T_AAAA:
1382: en = "AAAA";
1383: break;
1384: case T_PTR:
1385: en = "PTR";
1386: break;
1387: case T_MX:
1388: en = "MX";
1389: break;
1390: case T_TXT:
1391: en = "TXT";
1392: break;
1393: case T_KEY:
1394: en = "KEY";
1395: break;
1396: case T_CNAME:
1397: en = "CNAME";
1398: break;
1399: default:
1400: en = "UNKNOWN";
1401: break;
1402: }
1403: if (s + strlen (en) < end) {
1404: if (s + 1 < end)
1405: *s++ = ' ';
1406: strcpy (s, en);
1407: s += strlen (en);
1408: }
1409: if (u -> r_data) {
1410: if (s + 1 < end)
1411: *s++ = ' ';
1412: if (u -> r_type == T_TXT) {
1413: if (s + 1 < end)
1414: *s++ = '"';
1415: }
1416: if(u->r_type == T_KEY) {
1417: strcat(s, "<keydata>");
1418: s+=strlen("<keydata>");
1419: }
1420: else {
1421: if (s + u -> r_size < end) {
1422: memcpy (s, u -> r_data, u -> r_size);
1423: s += u -> r_size;
1424: if (u -> r_type == T_TXT) {
1425: if (s + 1 < end)
1426: *s++ = '"';
1427: }
1428: }
1429: }
1430: }
1431: if (position) {
1432: if (s + 1 < end)
1433: *s++ = ' ';
1434: if (s + strlen (op) < end) {
1435: strcpy (s, op);
1436: s += strlen (s);
1437: }
1438: }
1439: if (u == ISC_LIST_TAIL (*uq))
1440: break;
1441: }
1442: if (s == &obuf [0]) {
1443: strcpy (s, "empty update");
1444: s += strlen (s);
1445: }
1446: if (status == NOERROR)
1447: errorp = 0;
1448: else
1449: errorp = 1;
1450: en = isc_result_totext (status);
1451: #if 0
1452: switch (status) {
1453: case -1:
1454: en = "resolver failed";
1455: break;
1456:
1457: case FORMERR:
1458: en = "format error";
1459: break;
1460:
1461: case NOERROR:
1462: en = "succeeded";
1463: errorp = 0;
1464: break;
1465:
1466: case NOTAUTH:
1467: en = "not authorized";
1468: break;
1469:
1470: case NOTIMP:
1471: en = "not implemented";
1472: break;
1473:
1474: case NOTZONE:
1475: en = "not a single valid zone";
1476: break;
1477:
1478: case NXDOMAIN:
1479: en = "no such domain";
1480: break;
1481:
1482: case NXRRSET:
1483: en = "no such record";
1484: break;
1485:
1486: case REFUSED:
1487: en = "refused";
1488: break;
1489:
1490: case SERVFAIL:
1491: en = "server failed";
1492: break;
1493:
1494: case YXDOMAIN:
1495: en = "domain exists";
1496: break;
1497:
1498: case YXRRSET:
1499: en = "record exists";
1500: break;
1501:
1502: default:
1503: en = "unknown error";
1504: break;
1505: }
1506: #endif
1507:
1508: if (s + 2 < end) {
1509: *s++ = ':';
1510: *s++ = ' ';
1511: }
1512: if (s + strlen (en) < end) {
1513: strcpy (s, en);
1514: s += strlen (en);
1515: }
1516: if (s + 1 < end)
1517: *s++ = '.';
1518: *s++ = 0;
1519: if (errorp)
1520: log_error ("%s", obuf);
1521: else
1522: log_info ("%s", obuf);
1523: }
1524: #endif /* NSUPDATE */
1525:
1526: /* Format the given time as "A; # B", where A is the format
1527: * used by the parser, and B is the local time, for humans.
1528: */
1529: const char *
1530: print_time(TIME t)
1531: {
1532: static char buf[sizeof("epoch 9223372036854775807; "
1533: "# Wed Jun 30 21:49:08 2147483647")];
1534: static char buf1[sizeof("# Wed Jun 30 21:49:08 2147483647")];
1535: time_t since_epoch;
1536: /* The string: "6 2147483647/12/31 23:59:60;"
1537: * is smaller than the other, used to declare the buffer size, so
1538: * we can use one buffer for both.
1539: */
1540:
1541: if (t == MAX_TIME)
1542: return "never;";
1543:
1544: if (t < 0)
1545: return NULL;
1546:
1547: /* For those lucky enough to have a 128-bit time_t, ensure that
1548: * whatever (corrupt) value we're given doesn't exceed the static
1549: * buffer.
1550: */
1551: #if (MAX_TIME > 0x7fffffffffffffff)
1552: if (t > 0x7fffffffffffffff)
1553: return NULL;
1554: #endif
1555:
1556: if (db_time_format == LOCAL_TIME_FORMAT) {
1557: since_epoch = mktime(localtime(&t));
1558: if ((strftime(buf1, sizeof(buf1),
1559: "# %a %b %d %H:%M:%S %Y",
1560: localtime(&t)) == 0) ||
1561: (snprintf(buf, sizeof(buf), "epoch %lu; %s",
1562: (unsigned long)since_epoch, buf1) >= sizeof(buf)))
1563: return NULL;
1564:
1565: } else {
1566: /* No bounds check for the year is necessary - in this case,
1567: * strftime() will run out of space and assert an error.
1568: */
1569: if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;",
1570: gmtime(&t)) == 0)
1571: return NULL;
1572: }
1573:
1574: return buf;
1575: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>