]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
NDOize safeputs() and safeputchar()
[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 char * ts_format(register int, register int);
42
43 /*
44 * Print out a null-terminated filename (or other ascii string).
45 * If ep is NULL, assume no truncation check is needed.
46 * Return true if truncated.
47 */
48 int
49 fn_print(register const u_char *s, register const u_char *ep)
50 {
51 register int ret;
52 register u_char c;
53
54 ret = 1; /* assume truncated */
55 while (ep == NULL || s < ep) {
56 c = *s++;
57 if (c == '\0') {
58 ret = 0;
59 break;
60 }
61 if (!ND_ISASCII(c)) {
62 c = ND_TOASCII(c);
63 putchar('M');
64 putchar('-');
65 }
66 if (!ND_ISPRINT(c)) {
67 c ^= 0x40; /* DEL to ?, others to alpha */
68 putchar('^');
69 }
70 putchar(c);
71 }
72 return(ret);
73 }
74
75 /*
76 * Print out a counted filename (or other ascii string).
77 * If ep is NULL, assume no truncation check is needed.
78 * Return true if truncated.
79 */
80 int
81 fn_printn(register const u_char *s, register u_int n,
82 register const u_char *ep)
83 {
84 register u_char c;
85
86 while (n > 0 && (ep == NULL || s < ep)) {
87 n--;
88 c = *s++;
89 if (!ND_ISASCII(c)) {
90 c = ND_TOASCII(c);
91 putchar('M');
92 putchar('-');
93 }
94 if (!ND_ISPRINT(c)) {
95 c ^= 0x40; /* DEL to ?, others to alpha */
96 putchar('^');
97 }
98 putchar(c);
99 }
100 return (n == 0) ? 0 : 1;
101 }
102
103 /*
104 * Print out a null-padded filename (or other ascii string).
105 * If ep is NULL, assume no truncation check is needed.
106 * Return true if truncated.
107 */
108 int
109 fn_printzp(register const u_char *s, register u_int n,
110 register const u_char *ep)
111 {
112 register int ret;
113 register u_char c;
114
115 ret = 1; /* assume truncated */
116 while (n > 0 && (ep == NULL || s < ep)) {
117 n--;
118 c = *s++;
119 if (c == '\0') {
120 ret = 0;
121 break;
122 }
123 if (!ND_ISASCII(c)) {
124 c = ND_TOASCII(c);
125 putchar('M');
126 putchar('-');
127 }
128 if (!ND_ISPRINT(c)) {
129 c ^= 0x40; /* DEL to ?, others to alpha */
130 putchar('^');
131 }
132 putchar(c);
133 }
134 return (n == 0) ? 0 : ret;
135 }
136
137 /*
138 * Format the timestamp
139 */
140 char *
141 ts_format(register int sec, register int usec)
142 {
143 static char buf[sizeof("00:00:00.000000")];
144 (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u",
145 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
146
147 return buf;
148 }
149
150 /*
151 * Print the timestamp
152 */
153 void
154 ts_print(register const struct timeval *tvp)
155 {
156 register int s;
157 struct tm *tm;
158 time_t Time;
159 static unsigned b_sec;
160 static unsigned b_usec;
161 int d_usec;
162 int d_sec;
163
164 switch (tflag) {
165
166 case 0: /* Default */
167 s = (tvp->tv_sec + thiszone) % 86400;
168 (void)printf("%s ", ts_format(s, tvp->tv_usec));
169 break;
170
171 case 1: /* No time stamp */
172 break;
173
174 case 2: /* Unix timeval style */
175 (void)printf("%u.%06u ",
176 (unsigned)tvp->tv_sec,
177 (unsigned)tvp->tv_usec);
178 break;
179
180 case 3: /* Microseconds since previous packet */
181 case 5: /* Microseconds since first packet */
182 if (b_sec == 0) {
183 /* init timestamp for first packet */
184 b_usec = tvp->tv_usec;
185 b_sec = tvp->tv_sec;
186 }
187
188 d_usec = tvp->tv_usec - b_usec;
189 d_sec = tvp->tv_sec - b_sec;
190
191 while (d_usec < 0) {
192 d_usec += 1000000;
193 d_sec--;
194 }
195
196 (void)printf("%s ", ts_format(d_sec, d_usec));
197
198 if (tflag == 3) { /* set timestamp for last packet */
199 b_sec = tvp->tv_sec;
200 b_usec = tvp->tv_usec;
201 }
202 break;
203
204 case 4: /* Default + Date*/
205 s = (tvp->tv_sec + thiszone) % 86400;
206 Time = (tvp->tv_sec + thiszone) - s;
207 tm = gmtime (&Time);
208 if (!tm)
209 printf("Date fail ");
210 else
211 printf("%04d-%02d-%02d %s ",
212 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
213 ts_format(s, tvp->tv_usec));
214 break;
215 }
216 }
217
218 /*
219 * Print a relative number of seconds (e.g. hold time, prune timer)
220 * in the form 5m1s. This does no truncation, so 32230861 seconds
221 * is represented as 1y1w1d1h1m1s.
222 */
223 void
224 relts_print(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 (void)printf("0s");
233 return;
234 }
235 if (secs < 0) {
236 (void)printf("-");
237 secs = -secs;
238 }
239 while (secs > 0) {
240 if (secs >= *s) {
241 (void)printf("%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 (snapend - cp < len)
264 len = 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 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