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