xref: /netbsd/external/mpl/dhcp/dist/common/print.c (revision 13df4856)
1 /*	$NetBSD: print.c,v 1.3 2022/04/03 01:10:58 christos Exp $	*/
2 
3 /* print.c
4 
5    Turn data structures into printable text. */
6 
7 /*
8  * Copyright (C) 2004-2022 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  *   PO Box 360
25  *   Newmarket, NH 03857 USA
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: print.c,v 1.3 2022/04/03 01:10:58 christos Exp $");
33 
34 #include "dhcpd.h"
35 
36 int db_time_format = DEFAULT_TIME_FORMAT;
37 
quotify_string(const char * s,const char * file,int line)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 
quotify_buf(const unsigned char * s,unsigned len,char enclose_char,const char * file,int line)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 
print_base64(const unsigned char * buf,unsigned len,const char * file,int line)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 
print_hw_addr(htype,hlen,data)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 
print_lease(lease)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)
dump_packet_option(struct option_cache * oc,struct packet * packet,struct lease * lease,struct client_state * client,struct option_state * in_options,struct option_state * cfg_options,struct binding_scope ** scope,struct universe * u,void * foo)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 
dump_packet(tp)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 
dump_raw(buf,len)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 
hash_dump(table)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  */
print_hex_only(len,data,limit,buf)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  */
print_hex_or_string(len,data,limit,buf)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
print_hex(len,data,limit,buf_num)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 
print_dotted_quads(len,data)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 
print_dec_1(val)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 
print_dec_2(val)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 
print_subexpression(expr,buf,len)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 
print_expression(name,expr)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 
token_print_indent_concat(FILE * file,int col,int indent,const char * prefix,const char * suffix,...)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 
token_indent_data_string(FILE * file,int col,int indent,const char * prefix,const char * suffix,struct data_string * data)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 
token_print_indent(FILE * file,int col,int indent,const char * prefix,const char * suffix,const char * buf)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 
indent_spaces(FILE * file,int indent)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 *
print_time(TIME t)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 */
buf_to_hex(const unsigned char * s,unsigned len,const char * file,int line)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 */
format_lease_id(const unsigned char * s,unsigned len,int format,const char * file,int line)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  */
absolute_path(const char * orgpath)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