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