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