1 1.2 christos /* $NetBSD: print.c,v 1.3 2022/04/03 01:10:58 christos 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.3 christos * 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.3 christos * PO Box 360 25 1.3 christos * 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 christos __RCSID("$NetBSD: print.c,v 1.3 2022/04/03 01:10:58 christos 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