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