Remove old versions of tcpdump.
[dragonfly.git] / contrib / tcpdump-3.9 / 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.95.2.6 2006/02/08 01:40:09 hannes 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 null-terminated 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 out a null-padded filename (or other ascii string).
109  * If ep is NULL, assume no truncation check is needed.
110  * Return true if truncated.
111  */
112 int
113 fn_printzp(register const u_char *s, register u_int n,
114           register const u_char *ep)
115 {
116         register int ret;
117         register u_char c;
118
119         ret = 1;                        /* assume truncated */
120         while (n > 0 && (ep == NULL || s < ep)) {
121                 n--;
122                 c = *s++;
123                 if (c == '\0') {
124                         ret = 0;
125                         break;
126                 }
127                 if (!isascii(c)) {
128                         c = toascii(c);
129                         putchar('M');
130                         putchar('-');
131                 }
132                 if (!isprint(c)) {
133                         c ^= 0x40;      /* DEL to ?, others to alpha */
134                         putchar('^');
135                 }
136                 putchar(c);
137         }
138         return (n == 0) ? 0 : ret;
139 }
140
141 /*
142  * Print the timestamp
143  */
144 void
145 ts_print(register const struct timeval *tvp)
146 {
147         register int s;
148         struct tm *tm;
149         time_t Time;
150         static unsigned b_sec;
151         static unsigned b_usec;
152
153         switch (tflag) {
154
155         case 0: /* Default */
156                 s = (tvp->tv_sec + thiszone) % 86400;
157                 (void)printf("%02d:%02d:%02d.%06u ",
158                              s / 3600, (s % 3600) / 60, s % 60,
159                              (unsigned)tvp->tv_usec);
160                 break;
161
162         case 1: /* No time stamp */
163                 break;
164
165         case 2: /* Unix timeval style */
166                 (void)printf("%u.%06u ",
167                              (unsigned)tvp->tv_sec,
168                              (unsigned)tvp->tv_usec);
169                 break;
170
171         case 3: /* Microseconds since previous packet */
172                 if (b_sec == 0) {
173                         printf("000000 ");
174                 } else {
175                         int d_usec = tvp->tv_usec - b_usec;
176                         int d_sec = tvp->tv_sec - b_sec;
177
178                         while (d_usec < 0) {
179                                 d_usec += 1000000;
180                                 d_sec--;
181                         }
182                         if (d_sec)
183                                 printf("%d. ", d_sec);
184                         printf("%06d ", d_usec);
185                 }
186                 b_sec = tvp->tv_sec;
187                 b_usec = tvp->tv_usec;
188                 break;
189
190         case 4: /* Default + Date*/
191                 s = (tvp->tv_sec + thiszone) % 86400;
192                 Time = (tvp->tv_sec + thiszone) - s;
193                 tm = gmtime (&Time);
194                 if (!tm)
195                         printf("Date fail  ");
196                 else
197                         printf("%04d-%02d-%02d ",
198                                    tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
199                 printf("%02d:%02d:%02d.%06u ",
200                            s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec);
201                 break;
202         }
203 }
204
205 /*
206  * Print a relative number of seconds (e.g. hold time, prune timer)
207  * in the form 5m1s.  This does no truncation, so 32230861 seconds
208  * is represented as 1y1w1d1h1m1s.
209  */
210 void
211 relts_print(int secs)
212 {
213         static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
214         static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
215         const char **l = lengths;
216         const int *s = seconds;
217
218         if (secs == 0) {
219                 (void)printf("0s");
220                 return;
221         }
222         if (secs < 0) {
223                 (void)printf("-");
224                 secs = -secs;
225         }
226         while (secs > 0) {
227                 if (secs >= *s) {
228                         (void)printf("%d%s", secs / *s, *l);
229                         secs -= (secs / *s) * *s;
230                 }
231                 s++;
232                 l++;
233         }
234 }
235
236 /*
237  *  this is a generic routine for printing unknown data;
238  *  we pass on the linefeed plus indentation string to
239  *  get a proper output - returns 0 on error
240  */
241
242 int
243 print_unknown_data(const u_char *cp,const char *ident,int len)
244 {
245         if (len < 0) {
246                 printf("%sDissector error: print_unknown_data called with negative length",
247                     ident);
248                 return(0);
249         }
250         if (snapend - cp < len)
251                 len = snapend - cp;
252         if (len < 0) {
253                 printf("%sDissector error: print_unknown_data called with pointer past end of packet",
254                     ident);
255                 return(0);
256         }
257         hex_print(ident,cp,len);
258         return(1); /* everything is ok */
259 }
260
261 /*
262  * Convert a token value to a string; use "fmt" if not found.
263  */
264 const char *
265 tok2strbuf(register const struct tok *lp, register const char *fmt,
266            register int v, char *buf, size_t bufsize)
267 {
268         if (lp != NULL) {
269                 while (lp->s != NULL) {
270                         if (lp->v == v)
271                                 return (lp->s);
272                         ++lp;
273                 }
274         }
275         if (fmt == NULL)
276                 fmt = "#%d";
277
278         (void)snprintf(buf, bufsize, fmt, v);
279         return (const char *)buf;
280 }
281
282 /*
283  * Convert a token value to a string; use "fmt" if not found.
284  */
285 const char *
286 tok2str(register const struct tok *lp, register const char *fmt,
287         register int v)
288 {
289         static char buf[4][128];
290         static int idx = 0;
291         char *ret;
292
293         ret = buf[idx];
294         idx = (idx+1) & 3;
295         return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
296 }
297
298 /*
299  * Convert a bit token value to a string; use "fmt" if not found.
300  * this is useful for parsing bitfields, the output strings are comma seperated
301  */
302 char *
303 bittok2str(register const struct tok *lp, register const char *fmt,
304            register int v)
305 {
306         static char buf[256]; /* our stringbuffer */
307         int buflen=0;
308         register int rotbit; /* this is the bit we rotate through all bitpositions */
309         register int tokval;
310
311         while (lp->s != NULL && lp != NULL) {
312             tokval=lp->v;   /* load our first value */
313             rotbit=1;
314             while (rotbit != 0) {
315                 /*
316                  * lets AND the rotating bit with our token value
317                  * and see if we have got a match
318                  */
319                 if (tokval == (v&rotbit)) {
320                     /* ok we have found something */
321                     buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
322                     break;
323                 }
324                 rotbit=rotbit<<1; /* no match - lets shift and try again */
325             }
326             lp++;
327         }
328
329         if (buflen != 0) { /* did we find anything */
330             /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
331             buf[buflen-2] = '\0';
332             return (buf);
333         }
334         else {
335             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
336             if (fmt == NULL)
337                 fmt = "#%d";
338             (void)snprintf(buf, sizeof(buf), fmt, v);
339             return (buf);
340         }
341 }
342
343 /*
344  * Convert a value to a string using an array; the macro
345  * tok2strary() in <interface.h> is the public interface to
346  * this function and ensures that the second argument is
347  * correct for bounds-checking.
348  */
349 const char *
350 tok2strary_internal(register const char **lp, int n, register const char *fmt,
351         register int v)
352 {
353         static char buf[128];
354
355         if (v >= 0 && v < n && lp[v] != NULL)
356                 return lp[v];
357         if (fmt == NULL)
358                 fmt = "#%d";
359         (void)snprintf(buf, sizeof(buf), fmt, v);
360         return (buf);
361 }
362
363 /*
364  * Convert a 32-bit netmask to prefixlen if possible
365  * the function returns the prefix-len; if plen == -1
366  * then conversion was not possible;
367  */
368
369 int
370 mask2plen (u_int32_t mask)
371 {
372         u_int32_t bitmasks[33] = {
373                 0x00000000,
374                 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
375                 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
376                 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
377                 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
378                 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
379                 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
380                 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
381                 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
382         };
383         int prefix_len = 32;
384
385         /* let's see if we can transform the mask into a prefixlen */
386         while (prefix_len >= 0) {
387                 if (bitmasks[prefix_len] == mask)
388                         break;
389                 prefix_len--;
390         }
391         return (prefix_len);
392 }
393
394 /* VARARGS */
395 void
396 error(const char *fmt, ...)
397 {
398         va_list ap;
399
400         (void)fprintf(stderr, "%s: ", program_name);
401         va_start(ap, fmt);
402         (void)vfprintf(stderr, fmt, ap);
403         va_end(ap);
404         if (*fmt) {
405                 fmt += strlen(fmt);
406                 if (fmt[-1] != '\n')
407                         (void)fputc('\n', stderr);
408         }
409         exit(1);
410         /* NOTREACHED */
411 }
412
413 /* VARARGS */
414 void
415 warning(const char *fmt, ...)
416 {
417         va_list ap;
418
419         (void)fprintf(stderr, "%s: WARNING: ", program_name);
420         va_start(ap, fmt);
421         (void)vfprintf(stderr, fmt, ap);
422         va_end(ap);
423         if (*fmt) {
424                 fmt += strlen(fmt);
425                 if (fmt[-1] != '\n')
426                         (void)fputc('\n', stderr);
427         }
428 }
429
430 /*
431  * Copy arg vector into a new buffer, concatenating arguments with spaces.
432  */
433 char *
434 copy_argv(register char **argv)
435 {
436         register char **p;
437         register u_int len = 0;
438         char *buf;
439         char *src, *dst;
440
441         p = argv;
442         if (*p == 0)
443                 return 0;
444
445         while (*p)
446                 len += strlen(*p++) + 1;
447
448         buf = (char *)malloc(len);
449         if (buf == NULL)
450                 error("copy_argv: malloc");
451
452         p = argv;
453         dst = buf;
454         while ((src = *p++) != NULL) {
455                 while ((*dst++ = *src++) != '\0')
456                         ;
457                 dst[-1] = ' ';
458         }
459         dst[-1] = '\0';
460
461         return buf;
462 }
463
464 /*
465  * On Windows, we need to open the file in binary mode, so that
466  * we get all the bytes specified by the size we get from "fstat()".
467  * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
468  * we define it as 0 if it's not defined, so it does nothing.
469  */
470 #ifndef O_BINARY
471 #define O_BINARY        0
472 #endif
473
474 char *
475 read_infile(char *fname)
476 {
477         register int i, fd, cc;
478         register char *cp;
479         struct stat buf;
480
481         fd = open(fname, O_RDONLY|O_BINARY);
482         if (fd < 0)
483                 error("can't open %s: %s", fname, pcap_strerror(errno));
484
485         if (fstat(fd, &buf) < 0)
486                 error("can't stat %s: %s", fname, pcap_strerror(errno));
487
488         cp = malloc((u_int)buf.st_size + 1);
489         if (cp == NULL)
490                 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
491                         fname, pcap_strerror(errno));
492         cc = read(fd, cp, (u_int)buf.st_size);
493         if (cc < 0)
494                 error("read %s: %s", fname, pcap_strerror(errno));
495         if (cc != buf.st_size)
496                 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
497
498         close(fd);
499         /* replace "# comment" with spaces */
500         for (i = 0; i < cc; i++) {
501                 if (cp[i] == '#')
502                         while (i < cc && cp[i] != '\n')
503                                 cp[i++] = ' ';
504         }
505         cp[cc] = '\0';
506         return (cp);
507 }
508
509 void
510 safeputs(const char *s, int maxlen)
511 {
512     int idx = 0;
513         while (*s && idx < maxlen) {
514                 safeputchar(*s);
515                 idx++;
516                 s++;
517         }
518 }
519
520 void
521 safeputchar(int c)
522 {
523         unsigned char ch;
524
525         ch = (unsigned char)(c & 0xff);
526         if (ch < 0x80 && isprint(ch))
527                 printf("%c", ch);
528         else
529                 printf("\\%03o", ch);
530 }