117680Spst/*
239297Sfenner * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
2217680Spst#ifndef lint
23127668Sbmsstatic const char rcsid[] _U_ =
24190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.109 2007-01-29 09:59:42 hannes Exp $ (LBL)";
2517680Spst#endif
2617680Spst
2756893Sfenner#ifdef HAVE_CONFIG_H
2856893Sfenner#include "config.h"
2956893Sfenner#endif
3056893Sfenner
31127668Sbms#include <tcpdump-stdinc.h>
32127668Sbms
3317680Spst#include <sys/stat.h>
3417680Spst
3517680Spst#include <errno.h>
3617680Spst#ifdef HAVE_FCNTL_H
3717680Spst#include <fcntl.h>
3817680Spst#endif
3917680Spst#include <pcap.h>
4017680Spst#include <stdio.h>
4117680Spst#include <stdarg.h>
4217680Spst#include <stdlib.h>
4317680Spst#include <string.h>
4417680Spst
4517680Spst#include "interface.h"
4617680Spst
47190207Srpaulochar * ts_format(register int, register int);
48190207Srpaulo
4917680Spst/*
50147899Ssam * Print out a null-terminated filename (or other ascii string).
5117680Spst * If ep is NULL, assume no truncation check is needed.
5217680Spst * Return true if truncated.
5317680Spst */
5417680Spstint
5517680Spstfn_print(register const u_char *s, register const u_char *ep)
5617680Spst{
5717680Spst	register int ret;
5817680Spst	register u_char c;
5917680Spst
6017680Spst	ret = 1;			/* assume truncated */
6117680Spst	while (ep == NULL || s < ep) {
6217680Spst		c = *s++;
6317680Spst		if (c == '\0') {
6417680Spst			ret = 0;
6517680Spst			break;
6617680Spst		}
6717680Spst		if (!isascii(c)) {
6817680Spst			c = toascii(c);
6917680Spst			putchar('M');
7017680Spst			putchar('-');
7117680Spst		}
7217680Spst		if (!isprint(c)) {
7317680Spst			c ^= 0x40;	/* DEL to ?, others to alpha */
7417680Spst			putchar('^');
7517680Spst		}
7617680Spst		putchar(c);
7717680Spst	}
7817680Spst	return(ret);
7917680Spst}
8017680Spst
8117680Spst/*
8217680Spst * Print out a counted filename (or other ascii string).
8317680Spst * If ep is NULL, assume no truncation check is needed.
8417680Spst * Return true if truncated.
8517680Spst */
8617680Spstint
8717680Spstfn_printn(register const u_char *s, register u_int n,
8817680Spst	  register const u_char *ep)
8917680Spst{
9017680Spst	register u_char c;
9117680Spst
92127668Sbms	while (n > 0 && (ep == NULL || s < ep)) {
93127668Sbms		n--;
9417680Spst		c = *s++;
9517680Spst		if (!isascii(c)) {
9617680Spst			c = toascii(c);
9717680Spst			putchar('M');
9817680Spst			putchar('-');
9917680Spst		}
10017680Spst		if (!isprint(c)) {
10117680Spst			c ^= 0x40;	/* DEL to ?, others to alpha */
10217680Spst			putchar('^');
10317680Spst		}
10417680Spst		putchar(c);
10517680Spst	}
106127668Sbms	return (n == 0) ? 0 : 1;
10717680Spst}
10817680Spst
10917680Spst/*
110147899Ssam * Print out a null-padded filename (or other ascii string).
111147899Ssam * If ep is NULL, assume no truncation check is needed.
112147899Ssam * Return true if truncated.
113147899Ssam */
114147899Ssamint
115147899Ssamfn_printzp(register const u_char *s, register u_int n,
116147899Ssam	  register const u_char *ep)
117147899Ssam{
118147899Ssam	register int ret;
119147899Ssam	register u_char c;
120147899Ssam
121147899Ssam	ret = 1;			/* assume truncated */
122147899Ssam	while (n > 0 && (ep == NULL || s < ep)) {
123147899Ssam		n--;
124147899Ssam		c = *s++;
125147899Ssam		if (c == '\0') {
126147899Ssam			ret = 0;
127147899Ssam			break;
128147899Ssam		}
129147899Ssam		if (!isascii(c)) {
130147899Ssam			c = toascii(c);
131147899Ssam			putchar('M');
132147899Ssam			putchar('-');
133147899Ssam		}
134147899Ssam		if (!isprint(c)) {
135147899Ssam			c ^= 0x40;	/* DEL to ?, others to alpha */
136147899Ssam			putchar('^');
137147899Ssam		}
138147899Ssam		putchar(c);
139147899Ssam	}
140147899Ssam	return (n == 0) ? 0 : ret;
141147899Ssam}
142147899Ssam
143147899Ssam/*
144190207Srpaulo * Format the timestamp
145190207Srpaulo */
146190207Srpaulochar *
147190207Srpaulots_format(register int sec, register int usec)
148190207Srpaulo{
149190207Srpaulo        static char buf[sizeof("00:00:00.000000")];
150190207Srpaulo        (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u",
151190207Srpaulo               sec / 3600, (sec % 3600) / 60, sec % 60, usec);
152190207Srpaulo
153190207Srpaulo        return buf;
154190207Srpaulo}
155190207Srpaulo
156190207Srpaulo/*
15717680Spst * Print the timestamp
15817680Spst */
15917680Spstvoid
16017680Spstts_print(register const struct timeval *tvp)
16117680Spst{
16217680Spst	register int s;
16375115Sfenner	struct tm *tm;
16475115Sfenner	time_t Time;
16575115Sfenner	static unsigned b_sec;
16675115Sfenner	static unsigned b_usec;
167190207Srpaulo	int d_usec;
168190207Srpaulo	int d_sec;
16917680Spst
170146773Ssam	switch (tflag) {
171146773Ssam
172146773Ssam	case 0: /* Default */
17317680Spst		s = (tvp->tv_sec + thiszone) % 86400;
174190207Srpaulo                (void)printf("%s ", ts_format(s, tvp->tv_usec));
17575115Sfenner		break;
176146773Ssam
177146773Ssam	case 1: /* No time stamp */
178146773Ssam		break;
179146773Ssam
180146773Ssam	case 2: /* Unix timeval style */
18175115Sfenner		(void)printf("%u.%06u ",
18275115Sfenner			     (unsigned)tvp->tv_sec,
18375115Sfenner			     (unsigned)tvp->tv_usec);
18475115Sfenner		break;
185146773Ssam
186146773Ssam	case 3: /* Microseconds since previous packet */
187190207Srpaulo        case 5: /* Microseconds since first packet */
18875115Sfenner		if (b_sec == 0) {
189190207Srpaulo                        /* init timestamp for first packet */
190190207Srpaulo                        b_usec = tvp->tv_usec;
191190207Srpaulo                        b_sec = tvp->tv_sec;
192190207Srpaulo                }
193127668Sbms
194190207Srpaulo                d_usec = tvp->tv_usec - b_usec;
195190207Srpaulo                d_sec = tvp->tv_sec - b_sec;
196190207Srpaulo
197190207Srpaulo                while (d_usec < 0) {
198190207Srpaulo                    d_usec += 1000000;
199190207Srpaulo                    d_sec--;
200190207Srpaulo                }
201190207Srpaulo
202190207Srpaulo                (void)printf("%s ", ts_format(d_sec, d_usec));
203190207Srpaulo
204190207Srpaulo                if (tflag == 3) { /* set timestamp for last packet */
205190207Srpaulo                    b_sec = tvp->tv_sec;
206190207Srpaulo                    b_usec = tvp->tv_usec;
207190207Srpaulo                }
20875115Sfenner		break;
209146773Ssam
210146773Ssam	case 4: /* Default + Date*/
21175115Sfenner		s = (tvp->tv_sec + thiszone) % 86400;
21275115Sfenner		Time = (tvp->tv_sec + thiszone) - s;
213127668Sbms		tm = gmtime (&Time);
214127668Sbms		if (!tm)
215127668Sbms			printf("Date fail  ");
216127668Sbms		else
217190207Srpaulo			printf("%04d-%02d-%02d %s ",
218190207Srpaulo                               tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
219190207Srpaulo                               ts_format(s, tvp->tv_usec));
22075115Sfenner		break;
22117680Spst	}
22217680Spst}
22317680Spst
22417680Spst/*
22556893Sfenner * Print a relative number of seconds (e.g. hold time, prune timer)
22656893Sfenner * in the form 5m1s.  This does no truncation, so 32230861 seconds
22756893Sfenner * is represented as 1y1w1d1h1m1s.
22856893Sfenner */
22956893Sfennervoid
23056893Sfennerrelts_print(int secs)
23156893Sfenner{
23298524Sfenner	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
23398524Sfenner	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
23498524Sfenner	const char **l = lengths;
23598524Sfenner	const int *s = seconds;
23656893Sfenner
23798524Sfenner	if (secs == 0) {
23875115Sfenner		(void)printf("0s");
23975115Sfenner		return;
24056893Sfenner	}
24198524Sfenner	if (secs < 0) {
24298524Sfenner		(void)printf("-");
24398524Sfenner		secs = -secs;
24498524Sfenner	}
24575115Sfenner	while (secs > 0) {
24675115Sfenner		if (secs >= *s) {
24775115Sfenner			(void)printf("%d%s", secs / *s, *l);
24875115Sfenner			secs -= (secs / *s) * *s;
24975115Sfenner		}
25075115Sfenner		s++;
25175115Sfenner		l++;
25275115Sfenner	}
25356893Sfenner}
25456893Sfenner
25556893Sfenner/*
256127668Sbms *  this is a generic routine for printing unknown data;
257127668Sbms *  we pass on the linefeed plus indentation string to
258127668Sbms *  get a proper output - returns 0 on error
259127668Sbms */
260127668Sbms
261127668Sbmsint
262127668Sbmsprint_unknown_data(const u_char *cp,const char *ident,int len)
263127668Sbms{
264147899Ssam	if (len < 0) {
265147899Ssam		printf("%sDissector error: print_unknown_data called with negative length",
266147899Ssam		    ident);
267147899Ssam		return(0);
268147899Ssam	}
269147899Ssam	if (snapend - cp < len)
270147899Ssam		len = snapend - cp;
271147899Ssam	if (len < 0) {
272147899Ssam		printf("%sDissector error: print_unknown_data called with pointer past end of packet",
273147899Ssam		    ident);
274147899Ssam		return(0);
275147899Ssam	}
276127668Sbms        hex_print(ident,cp,len);
277127668Sbms	return(1); /* everything is ok */
278127668Sbms}
279127668Sbms
280127668Sbms/*
28117680Spst * Convert a token value to a string; use "fmt" if not found.
28217680Spst */
28317680Spstconst char *
284146773Ssamtok2strbuf(register const struct tok *lp, register const char *fmt,
285146773Ssam	   register int v, char *buf, size_t bufsize)
28617680Spst{
287147899Ssam	if (lp != NULL) {
288147899Ssam		while (lp->s != NULL) {
289147899Ssam			if (lp->v == v)
290147899Ssam				return (lp->s);
291147899Ssam			++lp;
292147899Ssam		}
29317680Spst	}
29417680Spst	if (fmt == NULL)
29517680Spst		fmt = "#%d";
296146773Ssam
297146773Ssam	(void)snprintf(buf, bufsize, fmt, v);
298146773Ssam	return (const char *)buf;
29917680Spst}
30017680Spst
30198524Sfenner/*
302146773Ssam * Convert a token value to a string; use "fmt" if not found.
303146773Ssam */
304146773Ssamconst char *
305146773Ssamtok2str(register const struct tok *lp, register const char *fmt,
306146773Ssam	register int v)
307146773Ssam{
308146773Ssam	static char buf[4][128];
309146773Ssam	static int idx = 0;
310146773Ssam	char *ret;
311146773Ssam
312146773Ssam	ret = buf[idx];
313146773Ssam	idx = (idx+1) & 3;
314146773Ssam	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
315146773Ssam}
316146773Ssam
317146773Ssam/*
318127668Sbms * Convert a bit token value to a string; use "fmt" if not found.
319190207Srpaulo * this is useful for parsing bitfields, the output strings are seperated
320190207Srpaulo * if the s field is positive.
321127668Sbms */
322190207Srpaulostatic char *
323190207Srpaulobittok2str_internal(register const struct tok *lp, register const char *fmt,
324190207Srpaulo	   register int v, register int sep)
325127668Sbms{
326127668Sbms        static char buf[256]; /* our stringbuffer */
327127668Sbms        int buflen=0;
328127668Sbms        register int rotbit; /* this is the bit we rotate through all bitpositions */
329127668Sbms        register int tokval;
330127668Sbms
331214478Srpaulo	while (lp != NULL && lp->s != NULL) {
332127668Sbms            tokval=lp->v;   /* load our first value */
333127668Sbms            rotbit=1;
334127668Sbms            while (rotbit != 0) {
335127668Sbms                /*
336127668Sbms                 * lets AND the rotating bit with our token value
337127668Sbms                 * and see if we have got a match
338127668Sbms                 */
339127668Sbms		if (tokval == (v&rotbit)) {
340127668Sbms                    /* ok we have found something */
341190207Srpaulo                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
342190207Srpaulo                                     lp->s, sep ? ", " : "");
343127668Sbms                    break;
344127668Sbms                }
345127668Sbms                rotbit=rotbit<<1; /* no match - lets shift and try again */
346127668Sbms            }
347127668Sbms            lp++;
348127668Sbms	}
349127668Sbms
350190207Srpaulo        /* user didn't want string seperation - no need to cut off trailing seperators */
351190207Srpaulo        if (!sep) {
352190207Srpaulo            return (buf);
353190207Srpaulo        }
354190207Srpaulo
355127668Sbms        if (buflen != 0) { /* did we find anything */
356127668Sbms            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
357127668Sbms            buf[buflen-2] = '\0';
358127668Sbms            return (buf);
359127668Sbms        }
360127668Sbms        else {
361127668Sbms            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
362127668Sbms            if (fmt == NULL)
363127668Sbms		fmt = "#%d";
364127668Sbms            (void)snprintf(buf, sizeof(buf), fmt, v);
365127668Sbms            return (buf);
366127668Sbms        }
367127668Sbms}
368127668Sbms
369127668Sbms/*
370190207Srpaulo * Convert a bit token value to a string; use "fmt" if not found.
371190207Srpaulo * this is useful for parsing bitfields, the output strings are not seperated.
372190207Srpaulo */
373190207Srpaulochar *
374190207Srpaulobittok2str_nosep(register const struct tok *lp, register const char *fmt,
375190207Srpaulo	   register int v)
376190207Srpaulo{
377190207Srpaulo    return (bittok2str_internal(lp, fmt, v, 0));
378190207Srpaulo}
379190207Srpaulo
380190207Srpaulo/*
381190207Srpaulo * Convert a bit token value to a string; use "fmt" if not found.
382190207Srpaulo * this is useful for parsing bitfields, the output strings are comma seperated.
383190207Srpaulo */
384190207Srpaulochar *
385190207Srpaulobittok2str(register const struct tok *lp, register const char *fmt,
386190207Srpaulo	   register int v)
387190207Srpaulo{
388190207Srpaulo    return (bittok2str_internal(lp, fmt, v, 1));
389190207Srpaulo}
390190207Srpaulo
391190207Srpaulo/*
39298524Sfenner * Convert a value to a string using an array; the macro
39398524Sfenner * tok2strary() in <interface.h> is the public interface to
39498524Sfenner * this function and ensures that the second argument is
39598524Sfenner * correct for bounds-checking.
39698524Sfenner */
39798524Sfennerconst char *
39898524Sfennertok2strary_internal(register const char **lp, int n, register const char *fmt,
39998524Sfenner	register int v)
40098524Sfenner{
40198524Sfenner	static char buf[128];
40217680Spst
40398524Sfenner	if (v >= 0 && v < n && lp[v] != NULL)
40498524Sfenner		return lp[v];
40598524Sfenner	if (fmt == NULL)
40698524Sfenner		fmt = "#%d";
40798524Sfenner	(void)snprintf(buf, sizeof(buf), fmt, v);
40898524Sfenner	return (buf);
40998524Sfenner}
41098524Sfenner
411127668Sbms/*
412127668Sbms * Convert a 32-bit netmask to prefixlen if possible
413127668Sbms * the function returns the prefix-len; if plen == -1
414127668Sbms * then conversion was not possible;
415127668Sbms */
416127668Sbms
417127668Sbmsint
418214478Srpaulomask2plen(u_int32_t mask)
419127668Sbms{
420127668Sbms	u_int32_t bitmasks[33] = {
421127668Sbms		0x00000000,
422127668Sbms		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
423127668Sbms		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
424127668Sbms		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
425127668Sbms		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
426127668Sbms		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
427127668Sbms		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
428127668Sbms		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
429127668Sbms		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
430127668Sbms	};
431127668Sbms	int prefix_len = 32;
432127668Sbms
433127668Sbms	/* let's see if we can transform the mask into a prefixlen */
434127668Sbms	while (prefix_len >= 0) {
435127668Sbms		if (bitmasks[prefix_len] == mask)
436127668Sbms			break;
437127668Sbms		prefix_len--;
438127668Sbms	}
439127668Sbms	return (prefix_len);
440127668Sbms}
441127668Sbms
442214478Srpaulo#ifdef INET6
443214478Srpauloint
444214478Srpaulomask62plen(const u_char *mask)
445214478Srpaulo{
446214478Srpaulo	u_char bitmasks[9] = {
447214478Srpaulo		0x00,
448214478Srpaulo		0x80, 0xc0, 0xe0, 0xf0,
449214478Srpaulo		0xf8, 0xfc, 0xfe, 0xff
450214478Srpaulo	};
451214478Srpaulo	int byte;
452214478Srpaulo	int cidr_len = 0;
453214478Srpaulo
454214478Srpaulo	for (byte = 0; byte < 16; byte++) {
455214478Srpaulo		u_int bits;
456214478Srpaulo
457214478Srpaulo		for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
458214478Srpaulo			if (mask[byte] == bitmasks[bits]) {
459214478Srpaulo				cidr_len += bits;
460214478Srpaulo				break;
461214478Srpaulo			}
462214478Srpaulo		}
463214478Srpaulo
464214478Srpaulo		if (mask[byte] != 0xff)
465214478Srpaulo			break;
466214478Srpaulo	}
467214478Srpaulo	return (cidr_len);
468214478Srpaulo}
469214478Srpaulo#endif /* INET6 */
470214478Srpaulo
47117680Spst/* VARARGS */
47275115Sfennervoid
47317680Spsterror(const char *fmt, ...)
47417680Spst{
47517680Spst	va_list ap;
47617680Spst
47717680Spst	(void)fprintf(stderr, "%s: ", program_name);
47817680Spst	va_start(ap, fmt);
47917680Spst	(void)vfprintf(stderr, fmt, ap);
48017680Spst	va_end(ap);
48117680Spst	if (*fmt) {
48217680Spst		fmt += strlen(fmt);
48317680Spst		if (fmt[-1] != '\n')
48417680Spst			(void)fputc('\n', stderr);
48517680Spst	}
48617680Spst	exit(1);
48717680Spst	/* NOTREACHED */
48817680Spst}
48917680Spst
49017680Spst/* VARARGS */
49117680Spstvoid
49217680Spstwarning(const char *fmt, ...)
49317680Spst{
49417680Spst	va_list ap;
49517680Spst
49617680Spst	(void)fprintf(stderr, "%s: WARNING: ", program_name);
49717680Spst	va_start(ap, fmt);
49817680Spst	(void)vfprintf(stderr, fmt, ap);
49917680Spst	va_end(ap);
50017680Spst	if (*fmt) {
50117680Spst		fmt += strlen(fmt);
50217680Spst		if (fmt[-1] != '\n')
50317680Spst			(void)fputc('\n', stderr);
50417680Spst	}
50517680Spst}
50617680Spst
50717680Spst/*
50817680Spst * Copy arg vector into a new buffer, concatenating arguments with spaces.
50917680Spst */
51017680Spstchar *
51117680Spstcopy_argv(register char **argv)
51217680Spst{
51317680Spst	register char **p;
51417680Spst	register u_int len = 0;
51517680Spst	char *buf;
51617680Spst	char *src, *dst;
51717680Spst
51817680Spst	p = argv;
51917680Spst	if (*p == 0)
52017680Spst		return 0;
52117680Spst
52217680Spst	while (*p)
52317680Spst		len += strlen(*p++) + 1;
52417680Spst
52517680Spst	buf = (char *)malloc(len);
52617680Spst	if (buf == NULL)
52717680Spst		error("copy_argv: malloc");
52817680Spst
52917680Spst	p = argv;
53017680Spst	dst = buf;
53117680Spst	while ((src = *p++) != NULL) {
53217680Spst		while ((*dst++ = *src++) != '\0')
53317680Spst			;
53417680Spst		dst[-1] = ' ';
53517680Spst	}
53617680Spst	dst[-1] = '\0';
53717680Spst
53817680Spst	return buf;
53917680Spst}
54017680Spst
541127668Sbms/*
542127668Sbms * On Windows, we need to open the file in binary mode, so that
543127668Sbms * we get all the bytes specified by the size we get from "fstat()".
544127668Sbms * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
545127668Sbms * we define it as 0 if it's not defined, so it does nothing.
546127668Sbms */
547127668Sbms#ifndef O_BINARY
548127668Sbms#define O_BINARY	0
549127668Sbms#endif
550127668Sbms
55117680Spstchar *
55217680Spstread_infile(char *fname)
55317680Spst{
554127668Sbms	register int i, fd, cc;
55517680Spst	register char *cp;
55617680Spst	struct stat buf;
55717680Spst
558127668Sbms	fd = open(fname, O_RDONLY|O_BINARY);
55917680Spst	if (fd < 0)
56017680Spst		error("can't open %s: %s", fname, pcap_strerror(errno));
56117680Spst
56217680Spst	if (fstat(fd, &buf) < 0)
56317680Spst		error("can't stat %s: %s", fname, pcap_strerror(errno));
56417680Spst
56517680Spst	cp = malloc((u_int)buf.st_size + 1);
56698524Sfenner	if (cp == NULL)
56798524Sfenner		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
56898524Sfenner			fname, pcap_strerror(errno));
56998524Sfenner	cc = read(fd, cp, (u_int)buf.st_size);
57017680Spst	if (cc < 0)
57117680Spst		error("read %s: %s", fname, pcap_strerror(errno));
57217680Spst	if (cc != buf.st_size)
57317680Spst		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
57417680Spst
575127668Sbms	close(fd);
576127668Sbms	/* replace "# comment" with spaces */
577127668Sbms	for (i = 0; i < cc; i++) {
578127668Sbms		if (cp[i] == '#')
579127668Sbms			while (i < cc && cp[i] != '\n')
580127668Sbms				cp[i++] = ' ';
581127668Sbms	}
582127668Sbms	cp[cc] = '\0';
58317680Spst	return (cp);
58417680Spst}
58575115Sfenner
58675115Sfennervoid
587172683Smlaiersafeputs(const char *s, int maxlen)
58875115Sfenner{
589190207Srpaulo	int idx = 0;
590190207Srpaulo
591172683Smlaier	while (*s && idx < maxlen) {
59275115Sfenner		safeputchar(*s);
593172683Smlaier                idx++;
59475115Sfenner		s++;
59575115Sfenner	}
59675115Sfenner}
59775115Sfenner
59875115Sfennervoid
59975115Sfennersafeputchar(int c)
60075115Sfenner{
60175115Sfenner	unsigned char ch;
60275115Sfenner
60375115Sfenner	ch = (unsigned char)(c & 0xff);
604111726Sfenner	if (ch < 0x80 && isprint(ch))
605111726Sfenner		printf("%c", ch);
60675115Sfenner	else
607190207Srpaulo		printf("\\0x%02x", ch);
60875115Sfenner}
609