1/* print.c
2
3   Turn data structures into printable text. */
4
5/*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
8 *
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.
12 *
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.
20 *
21 *   Internet Systems Consortium, Inc.
22 *   950 Charter Street
23 *   Redwood City, CA 94063
24 *   <info@isc.org>
25 *   http://www.isc.org/
26 *
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''.
33 */
34
35#ifndef lint
36static char copyright[] =
37"$Id: print.c,v 1.7 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38#endif /* not lint */
39
40#include "dhcpd.h"
41
42char *quotify_string (const char *s, const char *file, int line)
43{
44	unsigned len = 0;
45	const char *sp;
46	char *buf, *nsp;
47
48	for (sp = s; sp && *sp; sp++) {
49		if (*sp == ' ')
50			len++;
51		else if (!isascii (*sp) || !isprint ((unsigned char)*sp))
52			len += 4;
53		else if (*sp == '"' || *sp == '\\')
54			len += 2;
55		else
56			len++;
57	}
58
59	buf = dmalloc (len + 1, file, line);
60	if (buf) {
61		nsp = buf;
62		for (sp = s; sp && *sp; sp++) {
63			if (*sp == ' ')
64				*nsp++ = ' ';
65			else if (!isascii (*sp) || !isprint ((unsigned char)*sp)) {
66				sprintf (nsp, "\\%03o",
67					 *(const unsigned char *)sp);
68				nsp += 4;
69			} else if (*sp == '"' || *sp == '\\') {
70				*nsp++ = '\\';
71				*nsp++ = *sp;
72			} else
73				*nsp++ = *sp;
74		}
75		*nsp++ = 0;
76	}
77	return buf;
78}
79
80char *quotify_buf (const unsigned char *s, unsigned len,
81		   const char *file, int line)
82{
83	unsigned nulen = 0;
84	char *buf, *nsp;
85	int i;
86
87	for (i = 0; i < len; i++) {
88		if (s [i] == ' ')
89			nulen++;
90		else if (!isascii (s [i]) || !isprint (s [i]))
91			nulen += 4;
92		else if (s [i] == '"' || s [i] == '\\')
93			nulen += 2;
94		else
95			nulen++;
96	}
97
98	buf = dmalloc (nulen + 1, MDL);
99	if (buf) {
100		nsp = buf;
101		for (i = 0; i < len; i++) {
102			if (s [i] == ' ')
103				*nsp++ = ' ';
104			else if (!isascii (s [i]) || !isprint (s [i])) {
105				sprintf (nsp, "\\%03o", s [i]);
106				nsp += 4;
107			} else if (s [i] == '"' || s [i] == '\\') {
108				*nsp++ = '\\';
109				*nsp++ = s [i];
110			} else
111				*nsp++ = s [i];
112		}
113		*nsp++ = 0;
114	}
115	return buf;
116}
117
118char *print_base64 (const unsigned char *buf, unsigned len,
119		    const char *file, int line)
120{
121	char *s, *b;
122	unsigned bl;
123	int i;
124	unsigned val, extra;
125	static char to64 [] =
126	   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
127
128	bl = ((len * 4 + 2) / 3) + 1;
129	b = dmalloc (bl + 1, file, line);
130	if (!b)
131		return (char *)0;
132
133	i = 0;
134	s = b;
135	while (i != len) {
136		val = buf [i++];
137		extra = val & 3;
138		val = val >> 2;
139		*s++ = to64 [val];
140		if (i == len) {
141			*s++ = to64 [extra << 4];
142			*s++ = '=';
143			break;
144		}
145		val = (extra << 8) + buf [i++];
146		extra = val & 15;
147		val = val >> 4;
148		*s++ = to64 [val];
149		if (i == len) {
150			*s++ = to64 [extra << 2];
151			*s++ = '=';
152			break;
153		}
154		val = (extra << 8) + buf [i++];
155		extra = val & 0x3f;
156		val = val >> 6;
157		*s++ = to64 [val];
158		*s++ = to64 [extra];
159	}
160	if (!len)
161		*s++ = '=';
162	*s++ = 0;
163	if (s > b + bl + 1)
164		abort ();
165	return b;
166}
167
168char *print_hw_addr (htype, hlen, data)
169	int htype;
170	int hlen;
171	unsigned char *data;
172{
173	static char habuf [49];
174	char *s;
175	int i;
176
177	if (hlen <= 0)
178		habuf [0] = 0;
179	else {
180		s = habuf;
181		for (i = 0; i < hlen; i++) {
182			sprintf (s, "%02x", data [i]);
183			s += strlen (s);
184			*s++ = ':';
185		}
186		*--s = 0;
187	}
188	return habuf;
189}
190
191void print_lease (lease)
192	struct lease *lease;
193{
194	struct tm *t;
195	char tbuf [32];
196
197	log_debug ("  Lease %s",
198	       piaddr (lease -> ip_addr));
199
200	t = gmtime (&lease -> starts);
201	strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
202	log_debug ("  start %s", tbuf);
203
204	t = gmtime (&lease -> ends);
205	strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
206	log_debug ("  end %s", tbuf);
207
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>");
215}
216
217#if defined (DEBUG_PACKET)
218void dump_packet_option (struct option_cache *oc,
219			 struct packet *packet,
220			 struct lease *lease,
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)
226{
227	const char *name, *dot;
228	struct data_string ds;
229	memset (&ds, 0, sizeof ds);
230
231	if (u != &dhcp_universe) {
232		name = u -> name;
233		dot = ".";
234	} else {
235		name = "";
236		dot = "";
237	}
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);
245	}
246}
247
248void dump_packet (tp)
249	struct packet *tp;
250{
251	struct dhcp_packet *tdp = tp -> raw;
252
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) {
272		int i;
273
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,
279						      tp -> options,
280						      &global_scope,
281						      universes [i], 0,
282						      dump_packet_option);
283			}
284		}
285	}
286	log_debug ("%s", "");
287}
288#endif
289
290void dump_raw (buf, len)
291	const unsigned char *buf;
292	unsigned len;
293{
294	int i;
295	char lbuf [80];
296	int lbix = 0;
297
298/*
299          1         2         3         4         5         6         7
30001234567890123456789012345678901234567890123456789012345678901234567890123
301280: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   .................
302*/
303
304	memset(lbuf, ' ', 79);
305	lbuf [79] = 0;
306
307	for (i = 0; i < len; i++) {
308		if ((i & 15) == 0) {
309		  if (lbix) {
310		    	lbuf[53]=' ';
311			lbuf[54]=' ';
312			lbuf[55]=' ';
313			lbuf[73]='\0';
314			log_info ("%s", lbuf);
315		  }
316		  memset(lbuf, ' ', 79);
317		  lbuf [79] = 0;
318		  sprintf (lbuf, "%03x:", i);
319		  lbix = 4;
320		} else if ((i & 7) == 0)
321			lbuf [lbix++] = ' ';
322
323		if(isprint(buf[i])) {
324		  lbuf[56+(i%16)]=buf[i];
325		} else {
326		  lbuf[56+(i%16)]='.';
327		}
328
329		sprintf (&lbuf [lbix], " %02x", buf [i]);
330		lbix += 3;
331		lbuf[lbix]=' ';
332
333	}
334	lbuf[53]=' ';
335	lbuf[54]=' ';
336	lbuf[55]=' ';
337	lbuf[73]='\0';
338	log_info ("%s", lbuf);
339}
340
341void hash_dump (table)
342	struct hash_table *table;
343{
344	int i;
345	struct hash_bucket *bp;
346
347	if (!table)
348		return;
349
350	for (i = 0; i < table -> hash_count; i++) {
351		if (!table -> buckets [i])
352			continue;
353		log_info ("hash bucket %d:", i);
354		for (bp = table -> buckets [i]; bp; bp = bp -> next) {
355			if (bp -> len)
356				dump_raw (bp -> name, bp -> len);
357			else
358				log_info ("%s", (const char *)bp -> name);
359		}
360	}
361}
362
363#define HBLEN 60
364
365#define DECLARE_HEX_PRINTER(x)						      \
366char *print_hex##x (len, data, limit)					      \
367	unsigned len;							      \
368	const u_int8_t *data;						      \
369	unsigned limit;							      \
370{									      \
371									      \
372	static char hex_buf##x [HBLEN + 1];				      \
373	unsigned i;							      \
374									      \
375	if (limit > HBLEN)						      \
376		limit = HBLEN;						      \
377									      \
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]);		      \
383			}						      \
384			hex_buf##x [i * 3 - 1] = 0;			      \
385			return hex_buf##x;				      \
386		}							      \
387	}								      \
388	hex_buf##x [0] = '"';						      \
389	i = len;							      \
390	if (i > limit - 2)						      \
391		i = limit - 2;						      \
392	memcpy (&hex_buf##x [1], data, i);				      \
393	hex_buf##x [i + 1] = '"';					      \
394	hex_buf##x [i + 2] = 0;						      \
395	return hex_buf##x;						      \
396}
397
398DECLARE_HEX_PRINTER (_1)
399DECLARE_HEX_PRINTER (_2)
400DECLARE_HEX_PRINTER (_3)
401
402#define DQLEN	80
403
404char *print_dotted_quads (len, data)
405	unsigned len;
406	const u_int8_t *data;
407{
408	static char dq_buf [DQLEN + 1];
409	int i;
410	char *s, *last;
411
412	s = &dq_buf [0];
413	last = s;
414
415	i = 0;
416
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.
421	 */
422	do {
423		sprintf (s, "%u.%u.%u.%u, ",
424			 data [i], data [i + 1], data [i + 2], data [i + 3]);
425		s += strlen (s);
426		i += 4;
427	} while ((s - &dq_buf [0] > DQLEN - 21) &&
428		 i + 3 < len);
429	if (i == len)
430		s [-2] = 0;
431	else
432		strcpy (s, "...");
433	return dq_buf;
434}
435
436char *print_dec_1 (val)
437	unsigned long val;
438{
439	static char vbuf [32];
440	sprintf (vbuf, "%lu", val);
441	return vbuf;
442}
443
444char *print_dec_2 (val)
445	unsigned long val;
446{
447	static char vbuf [32];
448	sprintf (vbuf, "%lu", val);
449	return vbuf;
450}
451
452static unsigned print_subexpression PROTO ((struct expression *,
453					    char *, unsigned));
454
455static unsigned print_subexpression (expr, buf, len)
456	struct expression *expr;
457	char *buf;
458	unsigned len;
459{
460	unsigned rv, left;
461	const char *s;
462
463	switch (expr -> op) {
464	      case expr_none:
465		if (len > 3) {
466			strcpy (buf, "nil");
467			return 3;
468		}
469		break;
470
471	      case expr_match:
472		if (len > 7) {
473			strcpy (buf, "(match)");
474			return 7;
475		}
476		break;
477
478	      case expr_check:
479		rv = 10 + strlen (expr -> data.check -> name);
480		if (len > rv) {
481			sprintf (buf, "(check %s)",
482				 expr -> data.check -> name);
483			return rv;
484		}
485		break;
486
487	      case expr_equal:
488		if (len > 6) {
489			rv = 4;
490			strcpy (buf, "(eq ");
491			rv += print_subexpression (expr -> data.equal [0],
492						   buf + rv, len - rv - 2);
493			buf [rv++] = ' ';
494			rv += print_subexpression (expr -> data.equal [1],
495						   buf + rv, len - rv - 1);
496			buf [rv++] = ')';
497			buf [rv] = 0;
498			return rv;
499		}
500		break;
501
502	      case expr_not_equal:
503		if (len > 7) {
504			rv = 5;
505			strcpy (buf, "(neq ");
506			rv += print_subexpression (expr -> data.equal [0],
507						   buf + rv, len - rv - 2);
508			buf [rv++] = ' ';
509			rv += print_subexpression (expr -> data.equal [1],
510						   buf + rv, len - rv - 1);
511			buf [rv++] = ')';
512			buf [rv] = 0;
513			return rv;
514		}
515		break;
516
517	      case expr_substring:
518		if (len > 11) {
519			rv = 8;
520			strcpy (buf, "(substr ");
521			rv += print_subexpression (expr -> data.substring.expr,
522						   buf + rv, len - rv - 3);
523			buf [rv++] = ' ';
524			rv += print_subexpression
525				(expr -> data.substring.offset,
526				 buf + rv, len - rv - 2);
527			buf [rv++] = ' ';
528			rv += print_subexpression (expr -> data.substring.len,
529						   buf + rv, len - rv - 1);
530			buf [rv++] = ')';
531			buf [rv] = 0;
532			return rv;
533		}
534		break;
535
536	      case expr_suffix:
537		if (len > 10) {
538			rv = 8;
539			strcpy (buf, "(suffix ");
540			rv += print_subexpression (expr -> data.suffix.expr,
541						   buf + rv, len - rv - 2);
542			if (len > rv)
543				buf [rv++] = ' ';
544			rv += print_subexpression (expr -> data.suffix.len,
545						   buf + rv, len - rv - 1);
546			if (len > rv)
547				buf [rv++] = ')';
548			buf [rv] = 0;
549			return rv;
550		}
551		break;
552
553	      case expr_concat:
554		if (len > 10) {
555			rv = 8;
556			strcpy (buf, "(concat ");
557			rv += print_subexpression (expr -> data.concat [0],
558						   buf + rv, len - rv - 2);
559			buf [rv++] = ' ';
560			rv += print_subexpression (expr -> data.concat [1],
561						   buf + rv, len - rv - 1);
562			buf [rv++] = ')';
563			buf [rv] = 0;
564			return rv;
565		}
566		break;
567
568	      case expr_pick_first_value:
569		if (len > 8) {
570			rv = 6;
571			strcpy (buf, "(pick1st ");
572			rv += print_subexpression
573				(expr -> data.pick_first_value.car,
574				 buf + rv, len - rv - 2);
575			buf [rv++] = ' ';
576			rv += print_subexpression
577				(expr -> data.pick_first_value.cdr,
578				 buf + rv, len - rv - 1);
579			buf [rv++] = ')';
580			buf [rv] = 0;
581			return rv;
582		}
583		break;
584
585	      case expr_host_lookup:
586		rv = 15 + strlen (expr -> data.host_lookup -> hostname);
587		if (len > rv) {
588			sprintf (buf, "(dns-lookup %s)",
589				 expr -> data.host_lookup -> hostname);
590			return rv;
591		}
592		break;
593
594	      case expr_and:
595		s = "and";
596	      binop:
597		rv = strlen (s);
598		if (len > rv + 4) {
599			buf [0] = '(';
600			strcpy (&buf [1], s);
601			rv += 1;
602			buf [rv++] = ' ';
603			rv += print_subexpression (expr -> data.and [0],
604						buf + rv, len - rv - 2);
605			buf [rv++] = ' ';
606			rv += print_subexpression (expr -> data.and [1],
607						   buf + rv, len - rv - 1);
608			buf [rv++] = ')';
609			buf [rv] = 0;
610			return rv;
611		}
612		break;
613
614	      case expr_or:
615		s = "or";
616		goto binop;
617
618	      case expr_add:
619		s = "+";
620		goto binop;
621
622	      case expr_subtract:
623		s = "-";
624		goto binop;
625
626	      case expr_multiply:
627		s = "*";
628		goto binop;
629
630	      case expr_divide:
631		s = "/";
632		goto binop;
633
634	      case expr_remainder:
635		s = "%";
636		goto binop;
637
638	      case expr_binary_and:
639		s = "&";
640		goto binop;
641
642	      case expr_binary_or:
643		s = "|";
644		goto binop;
645
646	      case expr_binary_xor:
647		s = "^";
648		goto binop;
649
650	      case expr_not:
651		if (len > 6) {
652			rv = 5;
653			strcpy (buf, "(not ");
654			rv += print_subexpression (expr -> data.not,
655						   buf + rv, len - rv - 1);
656			buf [rv++] = ')';
657			buf [rv] = 0;
658			return rv;
659		}
660		break;
661
662	      case expr_config_option:
663		s = "cfg-option";
664		goto dooption;
665
666	      case expr_option:
667		s = "option";
668	      dooption:
669		rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
670			   strlen (expr -> data.option -> universe -> name));
671		if (len > rv) {
672			sprintf (buf, "(option %s.%s)",
673				 expr -> data.option -> universe -> name,
674				 expr -> data.option -> name);
675			return rv;
676		}
677		break;
678
679	      case expr_hardware:
680		if (len > 10) {
681			strcpy (buf, "(hardware)");
682			return 10;
683		}
684		break;
685
686	      case expr_packet:
687		if (len > 10) {
688			rv = 8;
689			strcpy (buf, "(substr ");
690			rv += print_subexpression (expr -> data.packet.offset,
691						   buf + rv, len - rv - 2);
692			buf [rv++] = ' ';
693			rv += print_subexpression (expr -> data.packet.len,
694						   buf + rv, len - rv - 1);
695			buf [rv++] = ')';
696			buf [rv] = 0;
697			return rv;
698		}
699		break;
700
701	      case expr_const_data:
702		s = print_hex_1 (expr -> data.const_data.len,
703				 expr -> data.const_data.data, len);
704		rv = strlen (s);
705		if (rv >= len)
706			rv = len - 1;
707		strncpy (buf, s, rv);
708		buf [rv] = 0;
709		return rv;
710
711	      case expr_encapsulate:
712		rv = 13;
713		strcpy (buf, "(encapsulate ");
714		rv += expr -> data.encapsulate.len;
715		if (rv + 2 > len)
716			rv = len - 2;
717		strncpy (buf,
718			 (const char *)expr -> data.encapsulate.data, rv - 13);
719		buf [rv++] = ')';
720		buf [rv++] = 0;
721		break;
722
723	      case expr_extract_int8:
724		if (len > 7) {
725			rv = 6;
726			strcpy (buf, "(int8 ");
727			rv += print_subexpression (expr -> data.extract_int,
728						   buf + rv, len - rv - 1);
729			buf [rv++] = ')';
730			buf [rv] = 0;
731			return rv;
732		}
733		break;
734
735	      case expr_extract_int16:
736		if (len > 8) {
737			rv = 7;
738			strcpy (buf, "(int16 ");
739			rv += print_subexpression (expr -> data.extract_int,
740						   buf + rv, len - rv - 1);
741			buf [rv++] = ')';
742			buf [rv] = 0;
743			return rv;
744		}
745		break;
746
747	      case expr_extract_int32:
748		if (len > 8) {
749			rv = 7;
750			strcpy (buf, "(int32 ");
751			rv += print_subexpression (expr -> data.extract_int,
752						   buf + rv, len - rv - 1);
753			buf [rv++] = ')';
754			buf [rv] = 0;
755			return rv;
756		}
757		break;
758
759	      case expr_encode_int8:
760		if (len > 7) {
761			rv = 6;
762			strcpy (buf, "(to-int8 ");
763			rv += print_subexpression (expr -> data.encode_int,
764						   buf + rv, len - rv - 1);
765			buf [rv++] = ')';
766			buf [rv] = 0;
767			return rv;
768		}
769		break;
770
771	      case expr_encode_int16:
772		if (len > 8) {
773			rv = 7;
774			strcpy (buf, "(to-int16 ");
775			rv += print_subexpression (expr -> data.encode_int,
776						   buf + rv, len - rv - 1);
777			buf [rv++] = ')';
778			buf [rv] = 0;
779			return rv;
780		}
781		break;
782
783	      case expr_encode_int32:
784		if (len > 8) {
785			rv = 7;
786			strcpy (buf, "(to-int32 ");
787			rv += print_subexpression (expr -> data.encode_int,
788						   buf + rv, len - rv - 1);
789			buf [rv++] = ')';
790			buf [rv] = 0;
791			return rv;
792		}
793		break;
794
795	      case expr_const_int:
796		s = print_dec_1 (expr -> data.const_int);
797		rv = strlen (s);
798		if (len > rv) {
799			strcpy (buf, s);
800			return rv;
801		}
802		break;
803
804	      case expr_exists:
805		rv = 10 + (strlen (expr -> data.option -> name) +
806			   strlen (expr -> data.option -> universe -> name));
807		if (len > rv) {
808			sprintf (buf, "(exists %s.%s)",
809				 expr -> data.option -> universe -> name,
810				 expr -> data.option -> name);
811			return rv;
812		}
813		break;
814
815	      case expr_variable_exists:
816		rv = 10 + strlen (expr -> data.variable);
817		if (len > rv) {
818			sprintf (buf, "(defined %s)", expr -> data.variable);
819			return rv;
820		}
821		break;
822
823	      case expr_variable_reference:
824		rv = strlen (expr -> data.variable);
825		if (len > rv) {
826			sprintf (buf, "%s", expr -> data.variable);
827			return rv;
828		}
829		break;
830
831	      case expr_known:
832		s = "known";
833	      astring:
834		rv = strlen (s);
835		if (len > rv) {
836			strcpy (buf, s);
837			return rv;
838		}
839		break;
840
841	      case expr_leased_address:
842		s = "leased-address";
843		goto astring;
844
845	      case expr_client_state:
846		s = "client-state";
847		goto astring;
848
849	      case expr_host_decl_name:
850		s = "host-decl-name";
851		goto astring;
852
853	      case expr_lease_time:
854		s = "lease-time";
855		goto astring;
856
857	      case expr_static:
858		s = "static";
859		goto astring;
860
861	      case expr_filename:
862		s = "filename";
863		goto astring;
864
865	      case expr_sname:
866		s = "server-name";
867		goto astring;
868
869	      case expr_reverse:
870		if (len > 11) {
871			rv = 13;
872			strcpy (buf, "(reverse ");
873			rv += print_subexpression (expr -> data.reverse.width,
874						   buf + rv, len - rv - 2);
875			buf [rv++] = ' ';
876			rv += print_subexpression (expr -> data.reverse.buffer,
877						   buf + rv, len - rv - 1);
878			buf [rv++] = ')';
879			buf [rv] = 0;
880			return rv;
881		}
882		break;
883
884	      case expr_binary_to_ascii:
885		if (len > 5) {
886			rv = 9;
887			strcpy (buf, "(b2a ");
888			rv += print_subexpression (expr -> data.b2a.base,
889						   buf + rv, len - rv - 4);
890			buf [rv++] = ' ';
891			rv += print_subexpression (expr -> data.b2a.width,
892						   buf + rv, len - rv - 3);
893			buf [rv++] = ' ';
894			rv += print_subexpression (expr -> data.b2a.seperator,
895						   buf + rv, len - rv - 2);
896			buf [rv++] = ' ';
897			rv += print_subexpression (expr -> data.b2a.buffer,
898						   buf + rv, len - rv - 1);
899			buf [rv++] = ')';
900			buf [rv] = 0;
901			return rv;
902		}
903		break;
904
905	      case expr_dns_transaction:
906		rv = 10;
907		if (len < rv + 2) {
908			buf [0] = '(';
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);
914				buf [rv++] = ' ';
915				expr = expr -> data.dns_transaction.cdr;
916			}
917			buf [rv - 1] = ')';
918			buf [rv] = 0;
919			return rv;
920		}
921		return 0;
922
923	      case expr_ns_delete:
924		s = "delete";
925		left = 4;
926		goto dodnsupd;
927	      case expr_ns_exists:
928		s = "exists";
929		left = 4;
930		goto dodnsupd;
931	      case expr_ns_not_exists:
932		s = "not_exists";
933		left = 4;
934		goto dodnsupd;
935	      case expr_ns_add:
936		s = "update";
937		left = 5;
938	      dodnsupd:
939		rv = strlen (s);
940		if (len > strlen (s) + 1) {
941			buf [0] = '(';
942			strcpy (buf + 1, s);
943			rv++;
944			buf [rv++] = ' ';
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]);
949			}
950			buf [rv++] = ' ';
951			left--;
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]);
956			}
957			buf [rv++] = ' ';
958			left--;
959			rv += print_subexpression
960				(expr -> data.ns_add.rrname,
961				 buf + rv, len - rv - left);
962			buf [rv++] = ' ';
963			left--;
964			rv += print_subexpression
965				(expr -> data.ns_add.rrdata,
966				 buf + rv, len - rv - left);
967			buf [rv++] = ' ';
968			left--;
969			rv += print_subexpression
970				(expr -> data.ns_add.ttl,
971				 buf + rv, len - rv - left);
972			buf [rv++] = ')';
973			buf [rv] = 0;
974			return rv;
975		}
976		break;
977
978	      case expr_null:
979		if (len > 6) {
980			strcpy (buf, "(null)");
981			return 6;
982		}
983		break;
984	      case expr_funcall:
985		rv = 12 + strlen (expr -> data.funcall.name);
986		if (len > rv + 1) {
987			strcpy (buf, "(funcall  ");
988			strcpy (buf + 9, expr -> data.funcall.name);
989			buf [rv++] = ' ';
990			rv += print_subexpression
991				(expr -> data.funcall.arglist, buf + rv,
992				 len - rv - 1);
993			buf [rv++] = ')';
994			buf [rv] = 0;
995			return rv;
996		}
997		break;
998
999	      case expr_arg:
1000		rv = print_subexpression (expr -> data.arg.val, buf, len);
1001		if (expr -> data.arg.next && rv + 2 < len) {
1002			buf [rv++] = ' ';
1003			rv += print_subexpression (expr -> data.arg.next,
1004						   buf, len);
1005			if (rv + 1 < len)
1006				buf [rv++] = 0;
1007			return rv;
1008		}
1009		break;
1010	      case expr_function:
1011		rv = 9;
1012		if (len > rv + 1) {
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)) {
1018					buf [rv - 1] = ' ';
1019					strcpy (&buf [rv], foo -> string);
1020					rv += strlen (foo -> string);
1021				}
1022			}
1023			buf [rv] = ')';
1024			buf [rv++] = 0;
1025			return rv;
1026		}
1027	}
1028	return 0;
1029}
1030
1031void print_expression (name, expr)
1032	const char *name;
1033	struct expression *expr;
1034{
1035	char buf [1024];
1036
1037	print_subexpression (expr, buf, sizeof buf);
1038	log_info ("%s: %s", name, buf);
1039}
1040
1041int token_print_indent_concat (FILE *file, int col,  int indent,
1042			       const char *prefix,
1043			       const char *suffix, ...)
1044{
1045	va_list list;
1046	unsigned len;
1047	char *s, *t, *u;
1048
1049	va_start (list, suffix);
1050	s = va_arg (list, char *);
1051	len = 0;
1052	while (s) {
1053		len += strlen (s);
1054		s = va_arg (list, char *);
1055	}
1056	va_end (list);
1057
1058	t = dmalloc (len + 1, MDL);
1059	if (!t)
1060		log_fatal ("token_print_indent: no memory for copy buffer");
1061
1062	va_start (list, suffix);
1063	s = va_arg (list, char *);
1064	u = t;
1065	while (s) {
1066		len = strlen (s);
1067		strcpy (u, s);
1068		u += len;
1069	}
1070	va_end (list);
1071
1072	len = token_print_indent (file, col, indent,
1073				  prefix, suffix, t);
1074	dfree (t, MDL);
1075	return col;
1076}
1077
1078int token_indent_data_string (FILE *file, int col, int indent,
1079			      const char *prefix, const char *suffix,
1080			      struct data_string *data)
1081{
1082	int i;
1083	char obuf [3];
1084
1085	/* See if this is just ASCII. */
1086	for (i = 0; i < data -> len; i++)
1087		if (!isascii (data -> data [i]) ||
1088		    !isprint (data -> data [i]))
1089			break;
1090
1091	/* If we have a purely ASCII string, output it as text. */
1092	if (i == data -> len) {
1093		char *buf = dmalloc (data -> len + 3, MDL);
1094		if (buf) {
1095			buf [0] = '"';
1096			memcpy (buf + 1, data -> data, data -> len);
1097			buf [data -> len + 1] = '"';
1098			buf [data -> len + 2] = 0;
1099			i = token_print_indent (file, col, indent,
1100						prefix, suffix, buf);
1101			dfree (buf, MDL);
1102			return i;
1103		}
1104	}
1105
1106	for (i = 0; i < data -> len; i++) {
1107		sprintf (obuf, "%2.2x", data -> data [i]);
1108		col = token_print_indent (file, col, indent,
1109					  i == 0 ? prefix : "",
1110					  (i + 1 == data -> len
1111					   ? suffix
1112					   : ""), obuf);
1113		if (i + 1 != data -> len)
1114			col = token_print_indent (file, col, indent,
1115						  prefix, suffix, ":");
1116	}
1117	return col;
1118}
1119
1120int token_print_indent (FILE *file, int col, int indent,
1121			const char *prefix,
1122			const char *suffix, const char *buf)
1123{
1124	int len = strlen (buf) + strlen (prefix);
1125	if (col + len > 79) {
1126		if (indent + len < 79) {
1127			indent_spaces (file, indent);
1128			col = indent;
1129		} else {
1130			indent_spaces (file, col);
1131			col = len > 79 ? 0 : 79 - len - 1;
1132		}
1133	} else if (prefix && *prefix) {
1134		fputs (prefix, file);
1135		col += strlen (prefix);
1136	}
1137	fputs (buf, file);
1138	col += len;
1139	if (suffix && *suffix) {
1140		if (col + strlen (suffix) > 79) {
1141			indent_spaces (file, indent);
1142			col = indent;
1143		} else {
1144			fputs (suffix, file);
1145			col += strlen (suffix);
1146		}
1147	}
1148	return col;
1149}
1150
1151void indent_spaces (FILE *file, int indent)
1152{
1153	int i;
1154	fputc ('\n', file);
1155	for (i = 0; i < indent; i++)
1156		fputc (' ', file);
1157}
1158
1159#if defined (NSUPDATE)
1160void print_dns_status (int status, ns_updque *uq)
1161{
1162	char obuf [1024];
1163	char *s = &obuf [0], *end = &obuf [1022];
1164	ns_updrec *u;
1165	int position;
1166	int ttlp;
1167	const char *predicate = "if", *en, *op;
1168	int errorp;
1169
1170	for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) {
1171		ttlp = 0;
1172
1173		switch (u -> r_opcode)
1174		{
1175		      case NXRRSET:
1176			op = "rrset doesn't exist";
1177			position = 1;
1178			break;
1179		      case YXRRSET:
1180			op = "rrset exists";
1181			position = 1;
1182			break;
1183		      case NXDOMAIN:
1184			op = "domain doesn't exist";
1185			position = 1;
1186			break;
1187		      case YXDOMAIN:
1188			op = "domain exists";
1189			position = 1;
1190			break;
1191		      case ADD:
1192			op = "add";
1193			position = 0;
1194			ttlp = 1;
1195			break;
1196		      case DELETE:
1197			op = "delete";
1198			position = 0;
1199			break;
1200		      default:
1201			op = "unknown";
1202			position = 0;
1203			break;
1204		}
1205		if (!position) {
1206			if (s != &obuf [0] && s + 1 < end)
1207				*s++ = ' ';
1208			if (s + strlen (op) < end) {
1209				strcpy (s, op);
1210				s += strlen (s);
1211			}
1212		} else {
1213			if (s != &obuf [0] && s + 1 < end)
1214				*s++ = ' ';
1215			if (s + strlen (predicate) < end) {
1216				strcpy (s, predicate);
1217				s += strlen (s);
1218			}
1219			predicate = "and";
1220		}
1221		if (u -> r_dname) {
1222			if (s + 1 < end)
1223				*s++ = ' ';
1224			if (s + strlen (u -> r_dname) < end) {
1225				strcpy (s, u -> r_dname);
1226				s += strlen (s);
1227			}
1228		}
1229		if (ttlp) {
1230			if (s + 1 < end)
1231				*s++ = ' ';
1232			/* 27 is as big as a ttl can get. */
1233			if (s + 27 < end) {
1234				sprintf (s, "%lu",
1235					 (unsigned long)(u -> r_ttl));
1236				s += strlen (s);
1237			}
1238		}
1239		switch (u -> r_class) {
1240		      case C_IN:
1241			en = "IN";
1242			break;
1243		      case C_CHAOS:
1244			en = "CHAOS";
1245			break;
1246		      case C_HS:
1247			en = "HS";
1248			break;
1249		      default:
1250			en = "UNKNOWN";
1251			break;
1252		}
1253		if (s + strlen (en) < end) {
1254			if (s + 1 < end)
1255				*s++ = ' ';
1256			strcpy (s, en);
1257			s += strlen (en);
1258		}
1259		switch (u -> r_type) {
1260		      case T_A:
1261			en = "A";
1262			break;
1263		      case T_PTR:
1264			en = "PTR";
1265			break;
1266		      case T_MX:
1267			en = "MX";
1268			break;
1269		      case T_TXT:
1270			en = "TXT";
1271			break;
1272		      case T_KEY:
1273			en = "KEY";
1274			break;
1275		      case T_CNAME:
1276			en = "CNAME";
1277			break;
1278		      default:
1279			en = "UNKNOWN";
1280			break;
1281		}
1282		if (s + strlen (en) < end) {
1283			if (s + 1 < end)
1284				*s++ = ' ';
1285			strcpy (s, en);
1286			s += strlen (en);
1287		}
1288		if (u -> r_data) {
1289			if (s + 1 < end)
1290				*s++ = ' ';
1291			if (u -> r_type == T_TXT) {
1292				if (s + 1 < end)
1293					*s++ = '"';
1294			}
1295			if(u->r_type == T_KEY) {
1296			  strcat(s, "<keydata>");
1297			  s+=strlen("<keydata>");
1298			}
1299			else {
1300			  if (s + u -> r_size < end) {
1301			    memcpy (s, u -> r_data, u -> r_size);
1302			    s += u -> r_size;
1303			    if (u -> r_type == T_TXT) {
1304			      if (s + 1 < end)
1305				*s++ = '"';
1306			    }
1307			  }
1308			}
1309		}
1310		if (position) {
1311			if (s + 1 < end)
1312				*s++ = ' ';
1313			if (s + strlen (op) < end) {
1314				strcpy (s, op);
1315				s += strlen (s);
1316			}
1317		}
1318		if (u == ISC_LIST_TAIL (*uq))
1319			break;
1320	}
1321	if (s == &obuf [0]) {
1322		strcpy (s, "empty update");
1323		s += strlen (s);
1324	}
1325	if (status == NOERROR)
1326		errorp = 0;
1327	else
1328		errorp = 1;
1329	en = isc_result_totext (status);
1330#if 0
1331	switch (status) {
1332	      case -1:
1333		en = "resolver failed";
1334		break;
1335
1336	      case FORMERR:
1337		en = "format error";
1338		break;
1339
1340	      case NOERROR:
1341		en = "succeeded";
1342		errorp = 0;
1343		break;
1344
1345	      case NOTAUTH:
1346		en = "not authorized";
1347		break;
1348
1349	      case NOTIMP:
1350		en = "not implemented";
1351		break;
1352
1353	      case NOTZONE:
1354		en = "not a single valid zone";
1355		break;
1356
1357	      case NXDOMAIN:
1358		en = "no such domain";
1359		break;
1360
1361	      case NXRRSET:
1362		en = "no such record";
1363		break;
1364
1365	      case REFUSED:
1366		en = "refused";
1367		break;
1368
1369	      case SERVFAIL:
1370		en = "server failed";
1371		break;
1372
1373	      case YXDOMAIN:
1374		en = "domain exists";
1375		break;
1376
1377	      case YXRRSET:
1378		en = "record exists";
1379		break;
1380
1381	      default:
1382		en = "unknown error";
1383		break;
1384	}
1385#endif
1386
1387	if (s + 2 < end) {
1388		*s++ = ':';
1389		*s++ = ' ';
1390	}
1391	if (s + strlen (en) < end) {
1392		strcpy (s, en);
1393		s += strlen (en);
1394	}
1395	if (s + 1 < end)
1396		*s++ = '.';
1397	*s++ = 0;
1398	if (errorp)
1399		log_error ("%s", obuf);
1400	else
1401		log_info ("%s", obuf);
1402}
1403#endif /* NSUPDATE */
1404