]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
fix a couple typos
[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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <tcpdump-stdinc.h>
27
28 #include <sys/stat.h>
29
30 #include <errno.h>
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "interface.h"
40
41 /*
42 * Print out a null-terminated filename (or other ascii string).
43 * If ep is NULL, assume no truncation check is needed.
44 * Return true if truncated.
45 */
46 int
47 fn_print(register const u_char *s, register const u_char *ep)
48 {
49 register int ret;
50 register u_char c;
51
52 ret = 1; /* assume truncated */
53 while (ep == NULL || s < ep) {
54 c = *s++;
55 if (c == '\0') {
56 ret = 0;
57 break;
58 }
59 if (!ND_ISASCII(c)) {
60 c = ND_TOASCII(c);
61 putchar('M');
62 putchar('-');
63 }
64 if (!ND_ISPRINT(c)) {
65 c ^= 0x40; /* DEL to ?, others to alpha */
66 putchar('^');
67 }
68 putchar(c);
69 }
70 return(ret);
71 }
72
73 /*
74 * Print out a counted filename (or other ascii string).
75 * If ep is NULL, assume no truncation check is needed.
76 * Return true if truncated.
77 */
78 int
79 fn_printn(register const u_char *s, register u_int n,
80 register const u_char *ep)
81 {
82 register u_char c;
83
84 while (n > 0 && (ep == NULL || s < ep)) {
85 n--;
86 c = *s++;
87 if (!ND_ISASCII(c)) {
88 c = ND_TOASCII(c);
89 putchar('M');
90 putchar('-');
91 }
92 if (!ND_ISPRINT(c)) {
93 c ^= 0x40; /* DEL to ?, others to alpha */
94 putchar('^');
95 }
96 putchar(c);
97 }
98 return (n == 0) ? 0 : 1;
99 }
100
101 /*
102 * Print out a null-padded filename (or other ascii string).
103 * If ep is NULL, assume no truncation check is needed.
104 * Return true if truncated.
105 */
106 int
107 fn_printzp(register const u_char *s, register u_int n,
108 register const u_char *ep)
109 {
110 register int ret;
111 register u_char c;
112
113 ret = 1; /* assume truncated */
114 while (n > 0 && (ep == NULL || s < ep)) {
115 n--;
116 c = *s++;
117 if (c == '\0') {
118 ret = 0;
119 break;
120 }
121 if (!ND_ISASCII(c)) {
122 c = ND_TOASCII(c);
123 putchar('M');
124 putchar('-');
125 }
126 if (!ND_ISPRINT(c)) {
127 c ^= 0x40; /* DEL to ?, others to alpha */
128 putchar('^');
129 }
130 putchar(c);
131 }
132 return (n == 0) ? 0 : ret;
133 }
134
135 /*
136 * Format the timestamp
137 */
138 static char *
139 ts_format(register int sec, register int usec)
140 {
141 static char buf[sizeof("00:00:00.000000")];
142 (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u",
143 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
144
145 return buf;
146 }
147
148 /*
149 * Print the timestamp
150 */
151 void
152 ts_print(netdissect_options *ndo,
153 register const struct timeval *tvp)
154 {
155 register int s;
156 struct tm *tm;
157 time_t Time;
158 static unsigned b_sec;
159 static unsigned b_usec;
160 int d_usec;
161 int d_sec;
162
163 switch (ndo->ndo_tflag) {
164
165 case 0: /* Default */
166 s = (tvp->tv_sec + thiszone) % 86400;
167 ND_PRINT((ndo, "%s ", ts_format(s, tvp->tv_usec)));
168 break;
169
170 case 1: /* No time stamp */
171 break;
172
173 case 2: /* Unix timeval style */
174 ND_PRINT((ndo, "%u.%06u ",
175 (unsigned)tvp->tv_sec,
176 (unsigned)tvp->tv_usec));
177 break;
178
179 case 3: /* Microseconds since previous packet */
180 case 5: /* Microseconds since first packet */
181 if (b_sec == 0) {
182 /* init timestamp for first packet */
183 b_usec = tvp->tv_usec;
184 b_sec = tvp->tv_sec;
185 }
186
187 d_usec = tvp->tv_usec - b_usec;
188 d_sec = tvp->tv_sec - b_sec;
189
190 while (d_usec < 0) {
191 d_usec += 1000000;
192 d_sec--;
193 }
194
195 ND_PRINT((ndo, "%s ", ts_format(d_sec, d_usec)));
196
197 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
198 b_sec = tvp->tv_sec;
199 b_usec = tvp->tv_usec;
200 }
201 break;
202
203 case 4: /* Default + Date*/
204 s = (tvp->tv_sec + thiszone) % 86400;
205 Time = (tvp->tv_sec + thiszone) - s;
206 tm = gmtime (&Time);
207 if (!tm)
208 ND_PRINT((ndo, "Date fail "));
209 else
210 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
211 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
212 ts_format(s, tvp->tv_usec)));
213 break;
214 }
215 }
216
217 /*
218 * Print a relative number of seconds (e.g. hold time, prune timer)
219 * in the form 5m1s. This does no truncation, so 32230861 seconds
220 * is represented as 1y1w1d1h1m1s.
221 */
222 void
223 relts_print(netdissect_options *ndo,
224 int secs)
225 {
226 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
227 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
228 const char **l = lengths;
229 const int *s = seconds;
230
231 if (secs == 0) {
232 ND_PRINT((ndo, "0s"));
233 return;
234 }
235 if (secs < 0) {
236 ND_PRINT((ndo, "-"));
237 secs = -secs;
238 }
239 while (secs > 0) {
240 if (secs >= *s) {
241 ND_PRINT((ndo, "%d%s", secs / *s, *l));
242 secs -= (secs / *s) * *s;
243 }
244 s++;
245 l++;
246 }
247 }
248
249 /*
250 * this is a generic routine for printing unknown data;
251 * we pass on the linefeed plus indentation string to
252 * get a proper output - returns 0 on error
253 */
254
255 int
256 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
257 {
258 if (len < 0) {
259 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
260 ident));
261 return(0);
262 }
263 if (ndo->ndo_snapend - cp < len)
264 len = ndo->ndo_snapend - cp;
265 if (len < 0) {
266 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
267 ident));
268 return(0);
269 }
270 hex_print(ndo, ident,cp,len);
271 return(1); /* everything is ok */
272 }
273
274 /*
275 * Convert a token value to a string; use "fmt" if not found.
276 */
277 const char *
278 tok2strbuf(register const struct tok *lp, register const char *fmt,
279 register u_int v, char *buf, size_t bufsize)
280 {
281 if (lp != NULL) {
282 while (lp->s != NULL) {
283 if (lp->v == v)
284 return (lp->s);
285 ++lp;
286 }
287 }
288 if (fmt == NULL)
289 fmt = "#%d";
290
291 (void)snprintf(buf, bufsize, fmt, v);
292 return (const char *)buf;
293 }
294
295 /*
296 * Convert a token value to a string; use "fmt" if not found.
297 */
298 const char *
299 tok2str(register const struct tok *lp, register const char *fmt,
300 register int v)
301 {
302 static char buf[4][128];
303 static int idx = 0;
304 char *ret;
305
306 ret = buf[idx];
307 idx = (idx+1) & 3;
308 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
309 }
310
311 /*
312 * Convert a bit token value to a string; use "fmt" if not found.
313 * this is useful for parsing bitfields, the output strings are seperated
314 * if the s field is positive.
315 */
316 static char *
317 bittok2str_internal(register const struct tok *lp, register const char *fmt,
318 register int v, register int sep)
319 {
320 static char buf[256]; /* our stringbuffer */
321 int buflen=0;
322 register int rotbit; /* this is the bit we rotate through all bitpositions */
323 register int tokval;
324
325 while (lp != NULL && lp->s != NULL) {
326 tokval=lp->v; /* load our first value */
327 rotbit=1;
328 while (rotbit != 0) {
329 /*
330 * lets AND the rotating bit with our token value
331 * and see if we have got a match
332 */
333 if (tokval == (v&rotbit)) {
334 /* ok we have found something */
335 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
336 lp->s, sep ? ", " : "");
337 break;
338 }
339 rotbit=rotbit<<1; /* no match - lets shift and try again */
340 }
341 lp++;
342 }
343
344 /* user didn't want string seperation - no need to cut off trailing seperators */
345 if (!sep) {
346 return (buf);
347 }
348
349 if (buflen != 0) { /* did we find anything */
350 /* yep, set the trailing zero 2 bytes before to eliminate the last comma & whitespace */
351 buf[buflen-2] = '\0';
352 return (buf);
353 }
354 else {
355 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
356 if (fmt == NULL)
357 fmt = "#%d";
358 (void)snprintf(buf, sizeof(buf), fmt, v);
359 return (buf);
360 }
361 }
362
363 /*
364 * Convert a bit token value to a string; use "fmt" if not found.
365 * this is useful for parsing bitfields, the output strings are not seperated.
366 */
367 char *
368 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
369 register int v)
370 {
371 return (bittok2str_internal(lp, fmt, v, 0));
372 }
373
374 /*
375 * Convert a bit token value to a string; use "fmt" if not found.
376 * this is useful for parsing bitfields, the output strings are comma seperated.
377 */
378 char *
379 bittok2str(register const struct tok *lp, register const char *fmt,
380 register int v)
381 {
382 return (bittok2str_internal(lp, fmt, v, 1));
383 }
384
385 /*
386 * Convert a value to a string using an array; the macro
387 * tok2strary() in <interface.h> is the public interface to
388 * this function and ensures that the second argument is
389 * correct for bounds-checking.
390 */
391 const char *
392 tok2strary_internal(register const char **lp, int n, register const char *fmt,
393 register int v)
394 {
395 static char buf[128];
396
397 if (v >= 0 && v < n && lp[v] != NULL)
398 return lp[v];
399 if (fmt == NULL)
400 fmt = "#%d";
401 (void)snprintf(buf, sizeof(buf), fmt, v);
402 return (buf);
403 }
404
405 /*
406 * Convert a 32-bit netmask to prefixlen if possible
407 * the function returns the prefix-len; if plen == -1
408 * then conversion was not possible;
409 */
410
411 int
412 mask2plen(u_int32_t mask)
413 {
414 u_int32_t bitmasks[33] = {
415 0x00000000,
416 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
417 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
418 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
419 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
420 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
421 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
422 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
423 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
424 };
425 int prefix_len = 32;
426
427 /* let's see if we can transform the mask into a prefixlen */
428 while (prefix_len >= 0) {
429 if (bitmasks[prefix_len] == mask)
430 break;
431 prefix_len--;
432 }
433 return (prefix_len);
434 }
435
436 #ifdef INET6
437 int
438 mask62plen(const u_char *mask)
439 {
440 u_char bitmasks[9] = {
441 0x00,
442 0x80, 0xc0, 0xe0, 0xf0,
443 0xf8, 0xfc, 0xfe, 0xff
444 };
445 int byte;
446 int cidr_len = 0;
447
448 for (byte = 0; byte < 16; byte++) {
449 u_int bits;
450
451 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
452 if (mask[byte] == bitmasks[bits]) {
453 cidr_len += bits;
454 break;
455 }
456 }
457
458 if (mask[byte] != 0xff)
459 break;
460 }
461 return (cidr_len);
462 }
463 #endif /* INET6 */
464
465 /* VARARGS */
466 void
467 error(const char *fmt, ...)
468 {
469 va_list ap;
470
471 (void)fprintf(stderr, "%s: ", program_name);
472 va_start(ap, fmt);
473 (void)vfprintf(stderr, fmt, ap);
474 va_end(ap);
475 if (*fmt) {
476 fmt += strlen(fmt);
477 if (fmt[-1] != '\n')
478 (void)fputc('\n', stderr);
479 }
480 exit(1);
481 /* NOTREACHED */
482 }
483
484 /* VARARGS */
485 void
486 warning(const char *fmt, ...)
487 {
488 va_list ap;
489
490 (void)fprintf(stderr, "%s: WARNING: ", program_name);
491 va_start(ap, fmt);
492 (void)vfprintf(stderr, fmt, ap);
493 va_end(ap);
494 if (*fmt) {
495 fmt += strlen(fmt);
496 if (fmt[-1] != '\n')
497 (void)fputc('\n', stderr);
498 }
499 }
500
501 /*
502 * Copy arg vector into a new buffer, concatenating arguments with spaces.
503 */
504 char *
505 copy_argv(register char **argv)
506 {
507 register char **p;
508 register u_int len = 0;
509 char *buf;
510 char *src, *dst;
511
512 p = argv;
513 if (*p == 0)
514 return 0;
515
516 while (*p)
517 len += strlen(*p++) + 1;
518
519 buf = (char *)malloc(len);
520 if (buf == NULL)
521 error("copy_argv: malloc");
522
523 p = argv;
524 dst = buf;
525 while ((src = *p++) != NULL) {
526 while ((*dst++ = *src++) != '\0')
527 ;
528 dst[-1] = ' ';
529 }
530 dst[-1] = '\0';
531
532 return buf;
533 }
534
535 /*
536 * On Windows, we need to open the file in binary mode, so that
537 * we get all the bytes specified by the size we get from "fstat()".
538 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
539 * we define it as 0 if it's not defined, so it does nothing.
540 */
541 #ifndef O_BINARY
542 #define O_BINARY 0
543 #endif
544
545 char *
546 read_infile(char *fname)
547 {
548 register int i, fd, cc;
549 register char *cp;
550 struct stat buf;
551
552 fd = open(fname, O_RDONLY|O_BINARY);
553 if (fd < 0)
554 error("can't open %s: %s", fname, pcap_strerror(errno));
555
556 if (fstat(fd, &buf) < 0)
557 error("can't stat %s: %s", fname, pcap_strerror(errno));
558
559 cp = malloc((u_int)buf.st_size + 1);
560 if (cp == NULL)
561 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
562 fname, pcap_strerror(errno));
563 cc = read(fd, cp, (u_int)buf.st_size);
564 if (cc < 0)
565 error("read %s: %s", fname, pcap_strerror(errno));
566 if (cc != buf.st_size)
567 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
568
569 close(fd);
570 /* replace "# comment" with spaces */
571 for (i = 0; i < cc; i++) {
572 if (cp[i] == '#')
573 while (i < cc && cp[i] != '\n')
574 cp[i++] = ' ';
575 }
576 cp[cc] = '\0';
577 return (cp);
578 }
579
580 void
581 safeputs(netdissect_options *ndo,
582 const u_char *s, const u_int maxlen)
583 {
584 u_int idx = 0;
585
586 while (*s && idx < maxlen) {
587 safeputchar(ndo, *s);
588 idx++;
589 s++;
590 }
591 }
592
593 void
594 safeputchar(netdissect_options *ndo,
595 const u_char c)
596 {
597 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
598 }
599
600 #ifdef LBL_ALIGN
601 /*
602 * Some compilers try to optimize memcpy(), using the alignment constraint
603 * on the argument pointer type. by using this function, we try to avoid the
604 * optimization.
605 */
606 void
607 unaligned_memcpy(void *p, const void *q, size_t l)
608 {
609 memcpy(p, q, l);
610 }
611
612 /* As with memcpy(), so with memcmp(). */
613 int
614 unaligned_memcmp(const void *p, const void *q, size_t l)
615 {
616 return (memcmp(p, q, l));
617 }
618 #endif