]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
change tok2str API to permit caller to provide
[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[] _U_ =
24 "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.92 2004-04-29 01:32:47 mcr 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 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 */
110 void
111 ts_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 */
169 void
170 relts_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
201 int
202 print_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 */
211 const char *
212 tok2strbuf(register const struct tok *lp, register const char *fmt,
213 register int v, char *buf, size_t bufsize)
214 {
215 while (lp->s != NULL) {
216 if (lp->v == v)
217 return (lp->s);
218 ++lp;
219 }
220 if (fmt == NULL)
221 fmt = "#%d";
222
223 (void)snprintf(buf, bufsize, fmt, v);
224 return (const char *)buf;
225 }
226
227 /*
228 * Convert a token value to a string; use "fmt" if not found.
229 */
230 const char *
231 tok2str(register const struct tok *lp, register const char *fmt,
232 register int v)
233 {
234 static char buf[4][128];
235 static int idx = 0;
236 char *ret;
237
238 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
239 }
240
241 /*
242 * Convert a bit token value to a string; use "fmt" if not found.
243 * this is useful for parsing bitfields, the output strings are comma seperated
244 */
245 char *
246 bittok2str(register const struct tok *lp, register const char *fmt,
247 register int v)
248 {
249 static char buf[256]; /* our stringbuffer */
250 int buflen=0;
251 register int rotbit; /* this is the bit we rotate through all bitpositions */
252 register int tokval;
253
254 while (lp->s != NULL) {
255 tokval=lp->v; /* load our first value */
256 rotbit=1;
257 while (rotbit != 0) {
258 /*
259 * lets AND the rotating bit with our token value
260 * and see if we have got a match
261 */
262 if (tokval == (v&rotbit)) {
263 /* ok we have found something */
264 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
265 break;
266 }
267 rotbit=rotbit<<1; /* no match - lets shift and try again */
268 }
269 lp++;
270 }
271
272 if (buflen != 0) { /* did we find anything */
273 /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
274 buf[buflen-2] = '\0';
275 return (buf);
276 }
277 else {
278 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
279 if (fmt == NULL)
280 fmt = "#%d";
281 (void)snprintf(buf, sizeof(buf), fmt, v);
282 return (buf);
283 }
284 }
285
286 /*
287 * Convert a value to a string using an array; the macro
288 * tok2strary() in <interface.h> is the public interface to
289 * this function and ensures that the second argument is
290 * correct for bounds-checking.
291 */
292 const char *
293 tok2strary_internal(register const char **lp, int n, register const char *fmt,
294 register int v)
295 {
296 static char buf[128];
297
298 if (v >= 0 && v < n && lp[v] != NULL)
299 return lp[v];
300 if (fmt == NULL)
301 fmt = "#%d";
302 (void)snprintf(buf, sizeof(buf), fmt, v);
303 return (buf);
304 }
305
306 /*
307 * Convert a 32-bit netmask to prefixlen if possible
308 * the function returns the prefix-len; if plen == -1
309 * then conversion was not possible;
310 */
311
312 int
313 mask2plen (u_int32_t mask)
314 {
315 u_int32_t bitmasks[33] = {
316 0x00000000,
317 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
318 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
319 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
320 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
321 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
322 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
323 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
324 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
325 };
326 int prefix_len = 32;
327
328 /* let's see if we can transform the mask into a prefixlen */
329 while (prefix_len >= 0) {
330 if (bitmasks[prefix_len] == mask)
331 break;
332 prefix_len--;
333 }
334 return (prefix_len);
335 }
336
337 /* VARARGS */
338 void
339 error(const char *fmt, ...)
340 {
341 va_list ap;
342
343 (void)fprintf(stderr, "%s: ", program_name);
344 va_start(ap, fmt);
345 (void)vfprintf(stderr, fmt, ap);
346 va_end(ap);
347 if (*fmt) {
348 fmt += strlen(fmt);
349 if (fmt[-1] != '\n')
350 (void)fputc('\n', stderr);
351 }
352 exit(1);
353 /* NOTREACHED */
354 }
355
356 /* VARARGS */
357 void
358 warning(const char *fmt, ...)
359 {
360 va_list ap;
361
362 (void)fprintf(stderr, "%s: WARNING: ", program_name);
363 va_start(ap, fmt);
364 (void)vfprintf(stderr, fmt, ap);
365 va_end(ap);
366 if (*fmt) {
367 fmt += strlen(fmt);
368 if (fmt[-1] != '\n')
369 (void)fputc('\n', stderr);
370 }
371 }
372
373 /*
374 * Copy arg vector into a new buffer, concatenating arguments with spaces.
375 */
376 char *
377 copy_argv(register char **argv)
378 {
379 register char **p;
380 register u_int len = 0;
381 char *buf;
382 char *src, *dst;
383
384 p = argv;
385 if (*p == 0)
386 return 0;
387
388 while (*p)
389 len += strlen(*p++) + 1;
390
391 buf = (char *)malloc(len);
392 if (buf == NULL)
393 error("copy_argv: malloc");
394
395 p = argv;
396 dst = buf;
397 while ((src = *p++) != NULL) {
398 while ((*dst++ = *src++) != '\0')
399 ;
400 dst[-1] = ' ';
401 }
402 dst[-1] = '\0';
403
404 return buf;
405 }
406
407 /*
408 * On Windows, we need to open the file in binary mode, so that
409 * we get all the bytes specified by the size we get from "fstat()".
410 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
411 * we define it as 0 if it's not defined, so it does nothing.
412 */
413 #ifndef O_BINARY
414 #define O_BINARY 0
415 #endif
416
417 char *
418 read_infile(char *fname)
419 {
420 register int i, fd, cc;
421 register char *cp;
422 struct stat buf;
423
424 fd = open(fname, O_RDONLY|O_BINARY);
425 if (fd < 0)
426 error("can't open %s: %s", fname, pcap_strerror(errno));
427
428 if (fstat(fd, &buf) < 0)
429 error("can't stat %s: %s", fname, pcap_strerror(errno));
430
431 cp = malloc((u_int)buf.st_size + 1);
432 if (cp == NULL)
433 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
434 fname, pcap_strerror(errno));
435 cc = read(fd, cp, (u_int)buf.st_size);
436 if (cc < 0)
437 error("read %s: %s", fname, pcap_strerror(errno));
438 if (cc != buf.st_size)
439 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
440
441 close(fd);
442 /* replace "# comment" with spaces */
443 for (i = 0; i < cc; i++) {
444 if (cp[i] == '#')
445 while (i < cc && cp[i] != '\n')
446 cp[i++] = ' ';
447 }
448 cp[cc] = '\0';
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 }