util.c revision 146773
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.95 2005/03/21 11:35:55 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
121	case 0: /* Default */
122		s = (tvp->tv_sec + thiszone) % 86400;
123		(void)printf("%02d:%02d:%02d.%06u ",
124			     s / 3600, (s % 3600) / 60, s % 60,
125			     (unsigned)tvp->tv_usec);
126		break;
127
128	case 1: /* No time stamp */
129		break;
130
131	case 2: /* Unix timeval style */
132		(void)printf("%u.%06u ",
133			     (unsigned)tvp->tv_sec,
134			     (unsigned)tvp->tv_usec);
135		break;
136
137	case 3: /* Microseconds since previous packet */
138		if (b_sec == 0) {
139			printf("000000 ");
140		} else {
141			int d_usec = tvp->tv_usec - b_usec;
142			int d_sec = tvp->tv_sec - b_sec;
143
144			while (d_usec < 0) {
145				d_usec += 1000000;
146				d_sec--;
147			}
148			if (d_sec)
149				printf("%d. ", d_sec);
150			printf("%06d ", d_usec);
151		}
152		b_sec = tvp->tv_sec;
153		b_usec = tvp->tv_usec;
154		break;
155
156	case 4: /* Default + Date*/
157		s = (tvp->tv_sec + thiszone) % 86400;
158		Time = (tvp->tv_sec + thiszone) - s;
159		tm = gmtime (&Time);
160		if (!tm)
161			printf("Date fail  ");
162		else
163			printf("%04d-%02d-%02d ",
164				   tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
165		printf("%02d:%02d:%02d.%06u ",
166			   s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec);
167		break;
168	}
169}
170
171/*
172 * Print a relative number of seconds (e.g. hold time, prune timer)
173 * in the form 5m1s.  This does no truncation, so 32230861 seconds
174 * is represented as 1y1w1d1h1m1s.
175 */
176void
177relts_print(int secs)
178{
179	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
180	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
181	const char **l = lengths;
182	const int *s = seconds;
183
184	if (secs == 0) {
185		(void)printf("0s");
186		return;
187	}
188	if (secs < 0) {
189		(void)printf("-");
190		secs = -secs;
191	}
192	while (secs > 0) {
193		if (secs >= *s) {
194			(void)printf("%d%s", secs / *s, *l);
195			secs -= (secs / *s) * *s;
196		}
197		s++;
198		l++;
199	}
200}
201
202/*
203 *  this is a generic routine for printing unknown data;
204 *  we pass on the linefeed plus indentation string to
205 *  get a proper output - returns 0 on error
206 */
207
208int
209print_unknown_data(const u_char *cp,const char *ident,int len)
210{
211        hex_print(ident,cp,len);
212	return(1); /* everything is ok */
213}
214
215/*
216 * Convert a token value to a string; use "fmt" if not found.
217 */
218const char *
219tok2strbuf(register const struct tok *lp, register const char *fmt,
220	   register int v, char *buf, size_t bufsize)
221{
222	while (lp->s != NULL && lp != NULL) {
223		if (lp->v == v)
224			return (lp->s);
225		++lp;
226	}
227	if (fmt == NULL)
228		fmt = "#%d";
229
230	(void)snprintf(buf, bufsize, fmt, v);
231	return (const char *)buf;
232}
233
234/*
235 * Convert a token value to a string; use "fmt" if not found.
236 */
237const char *
238tok2str(register const struct tok *lp, register const char *fmt,
239	register int v)
240{
241	static char buf[4][128];
242	static int idx = 0;
243	char *ret;
244
245	ret = buf[idx];
246	idx = (idx+1) & 3;
247	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
248}
249
250/*
251 * Convert a bit token value to a string; use "fmt" if not found.
252 * this is useful for parsing bitfields, the output strings are comma seperated
253 */
254char *
255bittok2str(register const struct tok *lp, register const char *fmt,
256	   register int v)
257{
258        static char buf[256]; /* our stringbuffer */
259        int buflen=0;
260        register int rotbit; /* this is the bit we rotate through all bitpositions */
261        register int tokval;
262
263	while (lp->s != NULL && lp != NULL) {
264            tokval=lp->v;   /* load our first value */
265            rotbit=1;
266            while (rotbit != 0) {
267                /*
268                 * lets AND the rotating bit with our token value
269                 * and see if we have got a match
270                 */
271		if (tokval == (v&rotbit)) {
272                    /* ok we have found something */
273                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
274                    break;
275                }
276                rotbit=rotbit<<1; /* no match - lets shift and try again */
277            }
278            lp++;
279	}
280
281        if (buflen != 0) { /* did we find anything */
282            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
283            buf[buflen-2] = '\0';
284            return (buf);
285        }
286        else {
287            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
288            if (fmt == NULL)
289		fmt = "#%d";
290            (void)snprintf(buf, sizeof(buf), fmt, v);
291            return (buf);
292        }
293}
294
295/*
296 * Convert a value to a string using an array; the macro
297 * tok2strary() in <interface.h> is the public interface to
298 * this function and ensures that the second argument is
299 * correct for bounds-checking.
300 */
301const char *
302tok2strary_internal(register const char **lp, int n, register const char *fmt,
303	register int v)
304{
305	static char buf[128];
306
307	if (v >= 0 && v < n && lp[v] != NULL)
308		return lp[v];
309	if (fmt == NULL)
310		fmt = "#%d";
311	(void)snprintf(buf, sizeof(buf), fmt, v);
312	return (buf);
313}
314
315/*
316 * Convert a 32-bit netmask to prefixlen if possible
317 * the function returns the prefix-len; if plen == -1
318 * then conversion was not possible;
319 */
320
321int
322mask2plen (u_int32_t mask)
323{
324	u_int32_t bitmasks[33] = {
325		0x00000000,
326		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
327		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
328		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
329		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
330		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
331		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
332		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
333		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
334	};
335	int prefix_len = 32;
336
337	/* let's see if we can transform the mask into a prefixlen */
338	while (prefix_len >= 0) {
339		if (bitmasks[prefix_len] == mask)
340			break;
341		prefix_len--;
342	}
343	return (prefix_len);
344}
345
346/* VARARGS */
347void
348error(const char *fmt, ...)
349{
350	va_list ap;
351
352	(void)fprintf(stderr, "%s: ", program_name);
353	va_start(ap, fmt);
354	(void)vfprintf(stderr, fmt, ap);
355	va_end(ap);
356	if (*fmt) {
357		fmt += strlen(fmt);
358		if (fmt[-1] != '\n')
359			(void)fputc('\n', stderr);
360	}
361	exit(1);
362	/* NOTREACHED */
363}
364
365/* VARARGS */
366void
367warning(const char *fmt, ...)
368{
369	va_list ap;
370
371	(void)fprintf(stderr, "%s: WARNING: ", program_name);
372	va_start(ap, fmt);
373	(void)vfprintf(stderr, fmt, ap);
374	va_end(ap);
375	if (*fmt) {
376		fmt += strlen(fmt);
377		if (fmt[-1] != '\n')
378			(void)fputc('\n', stderr);
379	}
380}
381
382/*
383 * Copy arg vector into a new buffer, concatenating arguments with spaces.
384 */
385char *
386copy_argv(register char **argv)
387{
388	register char **p;
389	register u_int len = 0;
390	char *buf;
391	char *src, *dst;
392
393	p = argv;
394	if (*p == 0)
395		return 0;
396
397	while (*p)
398		len += strlen(*p++) + 1;
399
400	buf = (char *)malloc(len);
401	if (buf == NULL)
402		error("copy_argv: malloc");
403
404	p = argv;
405	dst = buf;
406	while ((src = *p++) != NULL) {
407		while ((*dst++ = *src++) != '\0')
408			;
409		dst[-1] = ' ';
410	}
411	dst[-1] = '\0';
412
413	return buf;
414}
415
416/*
417 * On Windows, we need to open the file in binary mode, so that
418 * we get all the bytes specified by the size we get from "fstat()".
419 * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
420 * we define it as 0 if it's not defined, so it does nothing.
421 */
422#ifndef O_BINARY
423#define O_BINARY	0
424#endif
425
426char *
427read_infile(char *fname)
428{
429	register int i, fd, cc;
430	register char *cp;
431	struct stat buf;
432
433	fd = open(fname, O_RDONLY|O_BINARY);
434	if (fd < 0)
435		error("can't open %s: %s", fname, pcap_strerror(errno));
436
437	if (fstat(fd, &buf) < 0)
438		error("can't stat %s: %s", fname, pcap_strerror(errno));
439
440	cp = malloc((u_int)buf.st_size + 1);
441	if (cp == NULL)
442		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
443			fname, pcap_strerror(errno));
444	cc = read(fd, cp, (u_int)buf.st_size);
445	if (cc < 0)
446		error("read %s: %s", fname, pcap_strerror(errno));
447	if (cc != buf.st_size)
448		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
449
450	close(fd);
451	/* replace "# comment" with spaces */
452	for (i = 0; i < cc; i++) {
453		if (cp[i] == '#')
454			while (i < cc && cp[i] != '\n')
455				cp[i++] = ' ';
456	}
457	cp[cc] = '\0';
458	return (cp);
459}
460
461void
462safeputs(const char *s)
463{
464	while (*s) {
465		safeputchar(*s);
466		s++;
467	}
468}
469
470void
471safeputchar(int c)
472{
473	unsigned char ch;
474
475	ch = (unsigned char)(c & 0xff);
476	if (ch < 0x80 && isprint(ch))
477		printf("%c", ch);
478	else
479		printf("\\%03o", ch);
480}
481