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