util.c revision 127668
1/*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static const char rcsid[] _U_ =
24    "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.87.2.3 2003/12/29 22:42:23 hannes Exp $ (LBL)";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <tcpdump-stdinc.h>
32
33#include <sys/stat.h>
34
35#include <errno.h>
36#ifdef HAVE_FCNTL_H
37#include <fcntl.h>
38#endif
39#include <pcap.h>
40#include <stdio.h>
41#include <stdarg.h>
42#include <stdlib.h>
43#include <string.h>
44
45#include "interface.h"
46
47/*
48 * Print out a filename (or other ascii string).
49 * If ep is NULL, assume no truncation check is needed.
50 * Return true if truncated.
51 */
52int
53fn_print(register const u_char *s, register const u_char *ep)
54{
55	register int ret;
56	register u_char c;
57
58	ret = 1;			/* assume truncated */
59	while (ep == NULL || s < ep) {
60		c = *s++;
61		if (c == '\0') {
62			ret = 0;
63			break;
64		}
65		if (!isascii(c)) {
66			c = toascii(c);
67			putchar('M');
68			putchar('-');
69		}
70		if (!isprint(c)) {
71			c ^= 0x40;	/* DEL to ?, others to alpha */
72			putchar('^');
73		}
74		putchar(c);
75	}
76	return(ret);
77}
78
79/*
80 * Print out a counted filename (or other ascii string).
81 * If ep is NULL, assume no truncation check is needed.
82 * Return true if truncated.
83 */
84int
85fn_printn(register const u_char *s, register u_int n,
86	  register const u_char *ep)
87{
88	register u_char c;
89
90	while (n > 0 && (ep == NULL || s < ep)) {
91		n--;
92		c = *s++;
93		if (!isascii(c)) {
94			c = toascii(c);
95			putchar('M');
96			putchar('-');
97		}
98		if (!isprint(c)) {
99			c ^= 0x40;	/* DEL to ?, others to alpha */
100			putchar('^');
101		}
102		putchar(c);
103	}
104	return (n == 0) ? 0 : 1;
105}
106
107/*
108 * Print the timestamp
109 */
110void
111ts_print(register const struct timeval *tvp)
112{
113	register int s;
114	struct tm *tm;
115	time_t Time;
116	static unsigned b_sec;
117	static unsigned b_usec;
118
119	switch(tflag) {
120	case 1: /* Default */
121		s = (tvp->tv_sec + thiszone) % 86400;
122		(void)printf("%02d:%02d:%02d.%06u ",
123			     s / 3600, (s % 3600) / 60, s % 60,
124			     (unsigned)tvp->tv_usec);
125		break;
126	case -1: /* Unix timeval style */
127		(void)printf("%u.%06u ",
128			     (unsigned)tvp->tv_sec,
129			     (unsigned)tvp->tv_usec);
130		break;
131	case -2:
132		if (b_sec == 0) {
133			printf("000000 ");
134		} else {
135			int d_usec = tvp->tv_usec - b_usec;
136			int d_sec = tvp->tv_sec - b_sec;
137
138			while (d_usec < 0) {
139				d_usec += 1000000;
140				d_sec--;
141			}
142			if (d_sec)
143				printf("%d. ", d_sec);
144			printf("%06d ", d_usec);
145		}
146		b_sec = tvp->tv_sec;
147		b_usec = tvp->tv_usec;
148		break;
149	case -3: /* Default + Date*/
150		s = (tvp->tv_sec + thiszone) % 86400;
151		Time = (tvp->tv_sec + thiszone) - s;
152		tm = gmtime (&Time);
153		if (!tm)
154			printf("Date fail  ");
155		else
156			printf("%04d-%02d-%02d ",
157				   tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
158		printf("%02d:%02d:%02d.%06u ",
159			   s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec);
160		break;
161	}
162}
163
164/*
165 * Print a relative number of seconds (e.g. hold time, prune timer)
166 * in the form 5m1s.  This does no truncation, so 32230861 seconds
167 * is represented as 1y1w1d1h1m1s.
168 */
169void
170relts_print(int secs)
171{
172	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
173	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
174	const char **l = lengths;
175	const int *s = seconds;
176
177	if (secs == 0) {
178		(void)printf("0s");
179		return;
180	}
181	if (secs < 0) {
182		(void)printf("-");
183		secs = -secs;
184	}
185	while (secs > 0) {
186		if (secs >= *s) {
187			(void)printf("%d%s", secs / *s, *l);
188			secs -= (secs / *s) * *s;
189		}
190		s++;
191		l++;
192	}
193}
194
195/*
196 *  this is a generic routine for printing unknown data;
197 *  we pass on the linefeed plus indentation string to
198 *  get a proper output - returns 0 on error
199 */
200
201int
202print_unknown_data(const u_char *cp,const char *ident,int len)
203{
204        hex_print(ident,cp,len);
205	return(1); /* everything is ok */
206}
207
208/*
209 * Convert a token value to a string; use "fmt" if not found.
210 */
211const char *
212tok2str(register const struct tok *lp, register const char *fmt,
213	register int v)
214{
215	static char buf[128];
216
217	while (lp->s != NULL) {
218		if (lp->v == v)
219			return (lp->s);
220		++lp;
221	}
222	if (fmt == NULL)
223		fmt = "#%d";
224	(void)snprintf(buf, sizeof(buf), fmt, v);
225	return (buf);
226}
227
228/*
229 * Convert a bit token value to a string; use "fmt" if not found.
230 * this is useful for parsing bitfields, the output strings are comma seperated
231 */
232char *
233bittok2str(register const struct tok *lp, register const char *fmt,
234	register int v)
235{
236        static char buf[256]; /* our stringbuffer */
237        int buflen=0;
238        register int rotbit; /* this is the bit we rotate through all bitpositions */
239        register int tokval;
240
241	while (lp->s != NULL) {
242            tokval=lp->v;   /* load our first value */
243            rotbit=1;
244            while (rotbit != 0) {
245                /*
246                 * lets AND the rotating bit with our token value
247                 * and see if we have got a match
248                 */
249		if (tokval == (v&rotbit)) {
250                    /* ok we have found something */
251                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
252                    break;
253                }
254                rotbit=rotbit<<1; /* no match - lets shift and try again */
255            }
256            lp++;
257	}
258
259        if (buflen != 0) { /* did we find anything */
260            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
261            buf[buflen-2] = '\0';
262            return (buf);
263        }
264        else {
265            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
266            if (fmt == NULL)
267		fmt = "#%d";
268            (void)snprintf(buf, sizeof(buf), fmt, v);
269            return (buf);
270        }
271}
272
273/*
274 * Convert a value to a string using an array; the macro
275 * tok2strary() in <interface.h> is the public interface to
276 * this function and ensures that the second argument is
277 * correct for bounds-checking.
278 */
279const char *
280tok2strary_internal(register const char **lp, int n, register const char *fmt,
281	register int v)
282{
283	static char buf[128];
284
285	if (v >= 0 && v < n && lp[v] != NULL)
286		return lp[v];
287	if (fmt == NULL)
288		fmt = "#%d";
289	(void)snprintf(buf, sizeof(buf), fmt, v);
290	return (buf);
291}
292
293/*
294 * Convert a 32-bit netmask to prefixlen if possible
295 * the function returns the prefix-len; if plen == -1
296 * then conversion was not possible;
297 */
298
299int
300mask2plen (u_int32_t mask)
301{
302	u_int32_t bitmasks[33] = {
303		0x00000000,
304		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
305		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
306		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
307		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
308		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
309		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
310		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
311		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
312	};
313	int prefix_len = 32;
314
315	/* let's see if we can transform the mask into a prefixlen */
316	while (prefix_len >= 0) {
317		if (bitmasks[prefix_len] == mask)
318			break;
319		prefix_len--;
320	}
321	return (prefix_len);
322}
323
324/* VARARGS */
325void
326error(const char *fmt, ...)
327{
328	va_list ap;
329
330	(void)fprintf(stderr, "%s: ", program_name);
331	va_start(ap, fmt);
332	(void)vfprintf(stderr, fmt, ap);
333	va_end(ap);
334	if (*fmt) {
335		fmt += strlen(fmt);
336		if (fmt[-1] != '\n')
337			(void)fputc('\n', stderr);
338	}
339	exit(1);
340	/* NOTREACHED */
341}
342
343/* VARARGS */
344void
345warning(const char *fmt, ...)
346{
347	va_list ap;
348
349	(void)fprintf(stderr, "%s: WARNING: ", program_name);
350	va_start(ap, fmt);
351	(void)vfprintf(stderr, fmt, ap);
352	va_end(ap);
353	if (*fmt) {
354		fmt += strlen(fmt);
355		if (fmt[-1] != '\n')
356			(void)fputc('\n', stderr);
357	}
358}
359
360/*
361 * Copy arg vector into a new buffer, concatenating arguments with spaces.
362 */
363char *
364copy_argv(register char **argv)
365{
366	register char **p;
367	register u_int len = 0;
368	char *buf;
369	char *src, *dst;
370
371	p = argv;
372	if (*p == 0)
373		return 0;
374
375	while (*p)
376		len += strlen(*p++) + 1;
377
378	buf = (char *)malloc(len);
379	if (buf == NULL)
380		error("copy_argv: malloc");
381
382	p = argv;
383	dst = buf;
384	while ((src = *p++) != NULL) {
385		while ((*dst++ = *src++) != '\0')
386			;
387		dst[-1] = ' ';
388	}
389	dst[-1] = '\0';
390
391	return buf;
392}
393
394/*
395 * On Windows, we need to open the file in binary mode, so that
396 * we get all the bytes specified by the size we get from "fstat()".
397 * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
398 * we define it as 0 if it's not defined, so it does nothing.
399 */
400#ifndef O_BINARY
401#define O_BINARY	0
402#endif
403
404char *
405read_infile(char *fname)
406{
407	register int i, fd, cc;
408	register char *cp;
409	struct stat buf;
410
411	fd = open(fname, O_RDONLY|O_BINARY);
412	if (fd < 0)
413		error("can't open %s: %s", fname, pcap_strerror(errno));
414
415	if (fstat(fd, &buf) < 0)
416		error("can't stat %s: %s", fname, pcap_strerror(errno));
417
418	cp = malloc((u_int)buf.st_size + 1);
419	if (cp == NULL)
420		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
421			fname, pcap_strerror(errno));
422	cc = read(fd, cp, (u_int)buf.st_size);
423	if (cc < 0)
424		error("read %s: %s", fname, pcap_strerror(errno));
425	if (cc != buf.st_size)
426		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
427
428	close(fd);
429	/* replace "# comment" with spaces */
430	for (i = 0; i < cc; i++) {
431		if (cp[i] == '#')
432			while (i < cc && cp[i] != '\n')
433				cp[i++] = ' ';
434	}
435	cp[cc] = '\0';
436	return (cp);
437}
438
439void
440safeputs(const char *s)
441{
442	while (*s) {
443		safeputchar(*s);
444		s++;
445	}
446}
447
448void
449safeputchar(int c)
450{
451	unsigned char ch;
452
453	ch = (unsigned char)(c & 0xff);
454	if (ch < 0x80 && isprint(ch))
455		printf("%c", ch);
456	else
457		printf("\\%03o", ch);
458}
459