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