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