]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
Fix the parenthesization in the "alignment required but you can
[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.94 2004-06-15 23:05:06 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 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
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 */
176 void
177 relts_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
208 int
209 print_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 */
218 const char *
219 tok2strbuf(register const struct tok *lp, register const char *fmt,
220 register int v, char *buf, size_t bufsize)
221 {
222 while (lp->s != 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 */
237 const char *
238 tok2str(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 */
254 char *
255 bittok2str(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) {
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 */
301 const char *
302 tok2strary_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
321 int
322 mask2plen (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 */
347 void
348 error(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 */
366 void
367 warning(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 */
385 char *
386 copy_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
426 char *
427 read_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
461 void
462 safeputs(const char *s)
463 {
464 while (*s) {
465 safeputchar(*s);
466 s++;
467 }
468 }
469
470 void
471 safeputchar(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 }