]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
8fcf3e0cfc97113a4498e9e67735a379c4bc8518
[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 /*
23 * txtproto_print() derived from original code by Hannes Gredler
24 * (hannes@juniper.net):
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that: (1) source code
28 * distributions retain the above copyright notice and this paragraph
29 * in its entirety, and (2) distributions including binary code include
30 * the above copyright notice and this paragraph in its entirety in
31 * the documentation or other materials provided with the distribution.
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
33 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
34 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 */
37
38 #define NETDISSECT_REWORKED
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include <tcpdump-stdinc.h>
44
45 #include <sys/stat.h>
46
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
50 #include <stdio.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #include "interface.h"
56
57 /*
58 * timestamp display buffer size, the biggest size of both formats is needed
59 * sizeof("0000000000.000000000") > sizeof("00:00:00.000000000")
60 */
61 #define TS_BUF_SIZE sizeof("0000000000.000000000")
62
63 /*
64 * Print out a null-terminated filename (or other ascii string).
65 * If ep is NULL, assume no truncation check is needed.
66 * Return true if truncated.
67 */
68 int
69 fn_print(netdissect_options *ndo,
70 register const u_char *s, register const u_char *ep)
71 {
72 register int ret;
73 register u_char c;
74
75 ret = 1; /* assume truncated */
76 while (ep == NULL || s < ep) {
77 c = *s++;
78 if (c == '\0') {
79 ret = 0;
80 break;
81 }
82 if (!ND_ISASCII(c)) {
83 c = ND_TOASCII(c);
84 ND_PRINT((ndo, "M-"));
85 }
86 if (!ND_ISPRINT(c)) {
87 c ^= 0x40; /* DEL to ?, others to alpha */
88 ND_PRINT((ndo, "^"));
89 }
90 ND_PRINT((ndo, "%c", c));
91 }
92 return(ret);
93 }
94
95 /*
96 * Print out a counted filename (or other ascii string).
97 * If ep is NULL, assume no truncation check is needed.
98 * Return true if truncated.
99 */
100 int
101 fn_printn(netdissect_options *ndo,
102 register const u_char *s, register u_int n, register const u_char *ep)
103 {
104 register u_char c;
105
106 while (n > 0 && (ep == NULL || s < ep)) {
107 n--;
108 c = *s++;
109 if (!ND_ISASCII(c)) {
110 c = ND_TOASCII(c);
111 ND_PRINT((ndo, "M-"));
112 }
113 if (!ND_ISPRINT(c)) {
114 c ^= 0x40; /* DEL to ?, others to alpha */
115 ND_PRINT((ndo, "^"));
116 }
117 ND_PRINT((ndo, "%c", c));
118 }
119 return (n == 0) ? 0 : 1;
120 }
121
122 /*
123 * Print out a null-padded filename (or other ascii string).
124 * If ep is NULL, assume no truncation check is needed.
125 * Return true if truncated.
126 */
127 int
128 fn_printzp(netdissect_options *ndo,
129 register const u_char *s, register u_int n,
130 register const u_char *ep)
131 {
132 register int ret;
133 register u_char c;
134
135 ret = 1; /* assume truncated */
136 while (n > 0 && (ep == NULL || s < ep)) {
137 n--;
138 c = *s++;
139 if (c == '\0') {
140 ret = 0;
141 break;
142 }
143 if (!ND_ISASCII(c)) {
144 c = ND_TOASCII(c);
145 ND_PRINT((ndo, "M-"));
146 }
147 if (!ND_ISPRINT(c)) {
148 c ^= 0x40; /* DEL to ?, others to alpha */
149 ND_PRINT((ndo, "^"));
150 }
151 ND_PRINT((ndo, "%c", c));
152 }
153 return (n == 0) ? 0 : ret;
154 }
155
156 /*
157 * Format the timestamp
158 */
159 static char *
160 ts_format(netdissect_options *ndo
161 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
162 _U_
163 #endif
164 , int sec, int usec, char *buf)
165 {
166 const char *format;
167
168 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
169 switch (ndo->ndo_tstamp_precision) {
170
171 case PCAP_TSTAMP_PRECISION_MICRO:
172 format = "%02d:%02d:%02d.%06u";
173 break;
174
175 case PCAP_TSTAMP_PRECISION_NANO:
176 format = "%02d:%02d:%02d.%09u";
177 break;
178
179 default:
180 format = "%02d:%02d:%02d.{unknown}";
181 break;
182 }
183 #else
184 format = "%02d:%02d:%02d.%06u";
185 #endif
186
187 snprintf(buf, TS_BUF_SIZE, format,
188 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
189
190 return buf;
191 }
192
193 /*
194 * Print the timestamp
195 */
196 void
197 ts_print(netdissect_options *ndo,
198 register const struct timeval *tvp)
199 {
200 register int s;
201 struct tm *tm;
202 time_t Time;
203 static unsigned b_sec;
204 static unsigned b_usec;
205 int d_usec;
206 int d_sec;
207 char buf[TS_BUF_SIZE];
208
209 switch (ndo->ndo_tflag) {
210
211 case 0: /* Default */
212 s = (tvp->tv_sec + thiszone) % 86400;
213 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
214 break;
215
216 case 1: /* No time stamp */
217 break;
218
219 case 2: /* Unix timeval style */
220 ND_PRINT((ndo, "%u.%06u ",
221 (unsigned)tvp->tv_sec,
222 (unsigned)tvp->tv_usec));
223 break;
224
225 case 3: /* Microseconds since previous packet */
226 case 5: /* Microseconds since first packet */
227 if (b_sec == 0) {
228 /* init timestamp for first packet */
229 b_usec = tvp->tv_usec;
230 b_sec = tvp->tv_sec;
231 }
232
233 d_usec = tvp->tv_usec - b_usec;
234 d_sec = tvp->tv_sec - b_sec;
235
236 while (d_usec < 0) {
237 d_usec += 1000000;
238 d_sec--;
239 }
240
241 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec, buf)));
242
243 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
244 b_sec = tvp->tv_sec;
245 b_usec = tvp->tv_usec;
246 }
247 break;
248
249 case 4: /* Default + Date */
250 s = (tvp->tv_sec + thiszone) % 86400;
251 Time = (tvp->tv_sec + thiszone) - s;
252 tm = gmtime (&Time);
253 if (!tm)
254 ND_PRINT((ndo, "Date fail "));
255 else
256 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
257 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
258 ts_format(ndo, s, tvp->tv_usec, buf)));
259 break;
260 }
261 }
262
263 /*
264 * Print a relative number of seconds (e.g. hold time, prune timer)
265 * in the form 5m1s. This does no truncation, so 32230861 seconds
266 * is represented as 1y1w1d1h1m1s.
267 */
268 void
269 relts_print(netdissect_options *ndo,
270 int secs)
271 {
272 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
273 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
274 const char **l = lengths;
275 const int *s = seconds;
276
277 if (secs == 0) {
278 ND_PRINT((ndo, "0s"));
279 return;
280 }
281 if (secs < 0) {
282 ND_PRINT((ndo, "-"));
283 secs = -secs;
284 }
285 while (secs > 0) {
286 if (secs >= *s) {
287 ND_PRINT((ndo, "%d%s", secs / *s, *l));
288 secs -= (secs / *s) * *s;
289 }
290 s++;
291 l++;
292 }
293 }
294
295 /*
296 * this is a generic routine for printing unknown data;
297 * we pass on the linefeed plus indentation string to
298 * get a proper output - returns 0 on error
299 */
300
301 int
302 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
303 {
304 if (len < 0) {
305 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
306 ident));
307 return(0);
308 }
309 if (ndo->ndo_snapend - cp < len)
310 len = ndo->ndo_snapend - cp;
311 if (len < 0) {
312 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
313 ident));
314 return(0);
315 }
316 hex_print(ndo, ident,cp,len);
317 return(1); /* everything is ok */
318 }
319
320 /*
321 * Convert a token value to a string; use "fmt" if not found.
322 */
323 const char *
324 tok2strbuf(register const struct tok *lp, register const char *fmt,
325 register u_int v, char *buf, size_t bufsize)
326 {
327 if (lp != NULL) {
328 while (lp->s != NULL) {
329 if (lp->v == v)
330 return (lp->s);
331 ++lp;
332 }
333 }
334 if (fmt == NULL)
335 fmt = "#%d";
336
337 (void)snprintf(buf, bufsize, fmt, v);
338 return (const char *)buf;
339 }
340
341 /*
342 * Convert a token value to a string; use "fmt" if not found.
343 */
344 const char *
345 tok2str(register const struct tok *lp, register const char *fmt,
346 register u_int v)
347 {
348 static char buf[4][128];
349 static int idx = 0;
350 char *ret;
351
352 ret = buf[idx];
353 idx = (idx+1) & 3;
354 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
355 }
356
357 /*
358 * Convert a bit token value to a string; use "fmt" if not found.
359 * this is useful for parsing bitfields, the output strings are seperated
360 * if the s field is positive.
361 */
362 static char *
363 bittok2str_internal(register const struct tok *lp, register const char *fmt,
364 register u_int v, const char *sep)
365 {
366 static char buf[256]; /* our stringbuffer */
367 int buflen=0;
368 register u_int rotbit; /* this is the bit we rotate through all bitpositions */
369 register u_int tokval;
370 const char * sepstr = "";
371
372 while (lp != NULL && lp->s != NULL) {
373 tokval=lp->v; /* load our first value */
374 rotbit=1;
375 while (rotbit != 0) {
376 /*
377 * lets AND the rotating bit with our token value
378 * and see if we have got a match
379 */
380 if (tokval == (v&rotbit)) {
381 /* ok we have found something */
382 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
383 sepstr, lp->s);
384 sepstr = sep;
385 break;
386 }
387 rotbit=rotbit<<1; /* no match - lets shift and try again */
388 }
389 lp++;
390 }
391
392 if (buflen == 0)
393 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
394 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
395 return (buf);
396 }
397
398 /*
399 * Convert a bit token value to a string; use "fmt" if not found.
400 * this is useful for parsing bitfields, the output strings are not seperated.
401 */
402 char *
403 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
404 register u_int v)
405 {
406 return (bittok2str_internal(lp, fmt, v, ""));
407 }
408
409 /*
410 * Convert a bit token value to a string; use "fmt" if not found.
411 * this is useful for parsing bitfields, the output strings are comma seperated.
412 */
413 char *
414 bittok2str(register const struct tok *lp, register const char *fmt,
415 register u_int v)
416 {
417 return (bittok2str_internal(lp, fmt, v, ", "));
418 }
419
420 /*
421 * Convert a value to a string using an array; the macro
422 * tok2strary() in <interface.h> is the public interface to
423 * this function and ensures that the second argument is
424 * correct for bounds-checking.
425 */
426 const char *
427 tok2strary_internal(register const char **lp, int n, register const char *fmt,
428 register int v)
429 {
430 static char buf[128];
431
432 if (v >= 0 && v < n && lp[v] != NULL)
433 return lp[v];
434 if (fmt == NULL)
435 fmt = "#%d";
436 (void)snprintf(buf, sizeof(buf), fmt, v);
437 return (buf);
438 }
439
440 /*
441 * Convert a 32-bit netmask to prefixlen if possible
442 * the function returns the prefix-len; if plen == -1
443 * then conversion was not possible;
444 */
445
446 int
447 mask2plen(uint32_t mask)
448 {
449 uint32_t bitmasks[33] = {
450 0x00000000,
451 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
452 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
453 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
454 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
455 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
456 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
457 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
458 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
459 };
460 int prefix_len = 32;
461
462 /* let's see if we can transform the mask into a prefixlen */
463 while (prefix_len >= 0) {
464 if (bitmasks[prefix_len] == mask)
465 break;
466 prefix_len--;
467 }
468 return (prefix_len);
469 }
470
471 #ifdef INET6
472 int
473 mask62plen(const u_char *mask)
474 {
475 u_char bitmasks[9] = {
476 0x00,
477 0x80, 0xc0, 0xe0, 0xf0,
478 0xf8, 0xfc, 0xfe, 0xff
479 };
480 int byte;
481 int cidr_len = 0;
482
483 for (byte = 0; byte < 16; byte++) {
484 u_int bits;
485
486 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
487 if (mask[byte] == bitmasks[bits]) {
488 cidr_len += bits;
489 break;
490 }
491 }
492
493 if (mask[byte] != 0xff)
494 break;
495 }
496 return (cidr_len);
497 }
498 #endif /* INET6 */
499
500 /*
501 * Routine to print out information for text-based protocols such as FTP,
502 * HTTP, SMTP, RTSP, SIP, ....
503 */
504 #define MAX_TOKEN 128
505
506 /*
507 * Fetch a token from a packet, starting at the specified index,
508 * and return the length of the token.
509 *
510 * Returns 0 on error; yes, this is indistinguishable from an empty
511 * token, but an "empty token" isn't a valid token - it just means
512 * either a space character at the beginning of the line (this
513 * includes a blank line) or no more tokens remaining on the line.
514 */
515 static int
516 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
517 u_char *tbuf, size_t tbuflen)
518 {
519 size_t toklen = 0;
520
521 for (; idx < len; idx++) {
522 if (!ND_TTEST(*(pptr + idx))) {
523 /* ran past end of captured data */
524 return (0);
525 }
526 if (!isascii(*(pptr + idx))) {
527 /* not an ASCII character */
528 return (0);
529 }
530 if (isspace(*(pptr + idx))) {
531 /* end of token */
532 break;
533 }
534 if (!isprint(*(pptr + idx))) {
535 /* not part of a command token or response code */
536 return (0);
537 }
538 if (toklen + 2 > tbuflen) {
539 /* no room for this character and terminating '\0' */
540 return (0);
541 }
542 tbuf[toklen] = *(pptr + idx);
543 toklen++;
544 }
545 if (toklen == 0) {
546 /* no token */
547 return (0);
548 }
549 tbuf[toklen] = '\0';
550
551 /*
552 * Skip past any white space after the token, until we see
553 * an end-of-line (CR or LF).
554 */
555 for (; idx < len; idx++) {
556 if (!ND_TTEST(*(pptr + idx))) {
557 /* ran past end of captured data */
558 break;
559 }
560 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
561 /* end of line */
562 break;
563 }
564 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
565 /* not a printable ASCII character */
566 break;
567 }
568 if (!isspace(*(pptr + idx))) {
569 /* beginning of next token */
570 break;
571 }
572 }
573 return (idx);
574 }
575
576 /*
577 * Scan a buffer looking for a line ending - LF or CR-LF.
578 * Return the index of the character after the line ending or 0 if
579 * we encounter a non-ASCII or non-printable character or don't find
580 * the line ending.
581 */
582 static u_int
583 print_txt_line(netdissect_options *ndo, const char *protoname,
584 const char *prefix, const u_char *pptr, u_int idx, u_int len)
585 {
586 u_int startidx;
587 u_int linelen;
588
589 startidx = idx;
590 while (idx < len) {
591 ND_TCHECK(*(pptr+idx));
592 if (*(pptr+idx) == '\n') {
593 /*
594 * LF without CR; end of line.
595 * Skip the LF and print the line, with the
596 * exception of the LF.
597 */
598 linelen = idx - startidx;
599 idx++;
600 goto print;
601 } else if (*(pptr+idx) == '\r') {
602 /* CR - any LF? */
603 if ((idx+1) >= len) {
604 /* not in this packet */
605 return (0);
606 }
607 ND_TCHECK(*(pptr+idx+1));
608 if (*(pptr+idx+1) == '\n') {
609 /*
610 * CR-LF; end of line.
611 * Skip the CR-LF and print the line, with
612 * the exception of the CR-LF.
613 */
614 linelen = idx - startidx;
615 idx += 2;
616 goto print;
617 }
618
619 /*
620 * CR followed by something else; treat this
621 * as if it were binary data, and don't print
622 * it.
623 */
624 return (0);
625 } else if (!isascii(*(pptr+idx)) ||
626 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
627 /*
628 * Not a printable ASCII character and not a tab;
629 * treat this as if it were binary data, and
630 * don't print it.
631 */
632 return (0);
633 }
634 idx++;
635 }
636
637 /*
638 * All printable ASCII, but no line ending after that point
639 * in the buffer; treat this as if it were truncated.
640 */
641 trunc:
642 linelen = idx - startidx;
643 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
644 protoname));
645 return (0);
646
647 print:
648 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
649 return (idx);
650 }
651
652 void
653 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
654 const char *protoname, const char **cmds, u_int flags)
655 {
656 u_int idx, eol;
657 u_char token[MAX_TOKEN+1];
658 const char *cmd;
659 int is_reqresp = 0;
660 const char *pnp;
661
662 if (cmds != NULL) {
663 /*
664 * This protocol has more than just request and
665 * response lines; see whether this looks like a
666 * request or response.
667 */
668 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
669 if (idx != 0) {
670 /* Is this a valid request name? */
671 while ((cmd = *cmds++) != NULL) {
672 if (strcasecmp((const char *)token, cmd) == 0) {
673 /* Yes. */
674 is_reqresp = 1;
675 break;
676 }
677 }
678
679 /*
680 * No - is this a valid response code (3 digits)?
681 *
682 * Is this token the response code, or is the next
683 * token the response code?
684 */
685 if (flags & RESP_CODE_SECOND_TOKEN) {
686 /*
687 * Next token - get it.
688 */
689 idx = fetch_token(ndo, pptr, idx, len, token,
690 sizeof(token));
691 }
692 if (idx != 0) {
693 if (isdigit(token[0]) && isdigit(token[1]) &&
694 isdigit(token[2]) && token[3] == '\0') {
695 /* Yes. */
696 is_reqresp = 1;
697 }
698 }
699 }
700 } else {
701 /*
702 * This protocol has only request and response lines
703 * (e.g., FTP, where all the data goes over a
704 * different connection); assume the payload is
705 * a request or response.
706 */
707 is_reqresp = 1;
708 }
709
710 /* Capitalize the protocol name */
711 for (pnp = protoname; *pnp != '\0'; pnp++)
712 ND_PRINT((ndo, "%c", toupper(*pnp)));
713
714 if (is_reqresp) {
715 /*
716 * In non-verbose mode, just print the protocol, followed
717 * by the first line as the request or response info.
718 *
719 * In verbose mode, print lines as text until we run out
720 * of characters or see something that's not a
721 * printable-ASCII line.
722 */
723 if (ndo->ndo_vflag) {
724 /*
725 * We're going to print all the text lines in the
726 * request or response; just print the length
727 * on the first line of the output.
728 */
729 ND_PRINT((ndo, ", length: %u", len));
730 for (idx = 0;
731 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
732 idx = eol)
733 ;
734 } else {
735 /*
736 * Just print the first text line.
737 */
738 print_txt_line(ndo, protoname, ": ", pptr, 0, len);
739 }
740 }
741 }
742
743 /* VARARGS */
744 void
745 error(const char *fmt, ...)
746 {
747 va_list ap;
748
749 (void)fprintf(stderr, "%s: ", program_name);
750 va_start(ap, fmt);
751 (void)vfprintf(stderr, fmt, ap);
752 va_end(ap);
753 if (*fmt) {
754 fmt += strlen(fmt);
755 if (fmt[-1] != '\n')
756 (void)fputc('\n', stderr);
757 }
758 exit(1);
759 /* NOTREACHED */
760 }
761
762 /* VARARGS */
763 void
764 warning(const char *fmt, ...)
765 {
766 va_list ap;
767
768 (void)fprintf(stderr, "%s: WARNING: ", program_name);
769 va_start(ap, fmt);
770 (void)vfprintf(stderr, fmt, ap);
771 va_end(ap);
772 if (*fmt) {
773 fmt += strlen(fmt);
774 if (fmt[-1] != '\n')
775 (void)fputc('\n', stderr);
776 }
777 }
778
779 /*
780 * Copy arg vector into a new buffer, concatenating arguments with spaces.
781 */
782 char *
783 copy_argv(register char **argv)
784 {
785 register char **p;
786 register u_int len = 0;
787 char *buf;
788 char *src, *dst;
789
790 p = argv;
791 if (*p == 0)
792 return 0;
793
794 while (*p)
795 len += strlen(*p++) + 1;
796
797 buf = (char *)malloc(len);
798 if (buf == NULL)
799 error("copy_argv: malloc");
800
801 p = argv;
802 dst = buf;
803 while ((src = *p++) != NULL) {
804 while ((*dst++ = *src++) != '\0')
805 ;
806 dst[-1] = ' ';
807 }
808 dst[-1] = '\0';
809
810 return buf;
811 }
812
813 /*
814 * On Windows, we need to open the file in binary mode, so that
815 * we get all the bytes specified by the size we get from "fstat()".
816 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
817 * we define it as 0 if it's not defined, so it does nothing.
818 */
819 #ifndef O_BINARY
820 #define O_BINARY 0
821 #endif
822
823 char *
824 read_infile(char *fname)
825 {
826 register int i, fd, cc;
827 register char *cp;
828 struct stat buf;
829
830 fd = open(fname, O_RDONLY|O_BINARY);
831 if (fd < 0)
832 error("can't open %s: %s", fname, pcap_strerror(errno));
833
834 if (fstat(fd, &buf) < 0)
835 error("can't stat %s: %s", fname, pcap_strerror(errno));
836
837 cp = malloc((u_int)buf.st_size + 1);
838 if (cp == NULL)
839 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
840 fname, pcap_strerror(errno));
841 cc = read(fd, cp, (u_int)buf.st_size);
842 if (cc < 0)
843 error("read %s: %s", fname, pcap_strerror(errno));
844 if (cc != buf.st_size)
845 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
846
847 close(fd);
848 /* replace "# comment" with spaces */
849 for (i = 0; i < cc; i++) {
850 if (cp[i] == '#')
851 while (i < cc && cp[i] != '\n')
852 cp[i++] = ' ';
853 }
854 cp[cc] = '\0';
855 return (cp);
856 }
857
858 void
859 safeputs(netdissect_options *ndo,
860 const u_char *s, const u_int maxlen)
861 {
862 u_int idx = 0;
863
864 while (*s && idx < maxlen) {
865 safeputchar(ndo, *s);
866 idx++;
867 s++;
868 }
869 }
870
871 void
872 safeputchar(netdissect_options *ndo,
873 const u_char c)
874 {
875 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
876 }
877
878 #ifdef LBL_ALIGN
879 /*
880 * Some compilers try to optimize memcpy(), using the alignment constraint
881 * on the argument pointer type. by using this function, we try to avoid the
882 * optimization.
883 */
884 void
885 unaligned_memcpy(void *p, const void *q, size_t l)
886 {
887 memcpy(p, q, l);
888 }
889
890 /* As with memcpy(), so with memcmp(). */
891 int
892 unaligned_memcmp(const void *p, const void *q, size_t l)
893 {
894 return (memcmp(p, q, l));
895 }
896 #endif