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