4 * $Id: util.c,v 1.67 2003/07/11 06:45:59 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef HAVE_SYS_STAT_H
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
54 typedef int mode_t; /* for win32 */
58 #include <zlib.h> /* to get the libz version number */
64 #include "capture-wpcap.h"
66 #endif /* HAVE_LIBPCAP */
71 #include <net-snmp/version.h>
72 #endif /* HAVE_NET_SNMP */
75 #include <ucd-snmp/version.h>
76 #endif /* HAVE_UCD_SNMP */
78 #endif /* HAVE_SOME_SNMP */
80 #ifdef HAVE_SYS_UTSNAME_H
81 #include <sys/utsname.h>
87 * See whether the last line in the string goes past column 80; if so,
88 * replace the blank at the specified point with a newline.
91 do_word_wrap(GString *str, gint point)
95 line_begin = strrchr(str->str, '\n');
96 if (line_begin == NULL)
97 line_begin = str->str;
100 if (strlen(line_begin) > 80) {
101 g_assert(str->str[point] == ' ');
102 str->str[point] = '\n';
107 * Get various library compile-time versions and append them to
108 * the specified GString.
111 get_compiled_version_info(GString *str)
114 #ifdef HAVE_PCAP_VERSION
115 extern char pcap_version[];
116 #endif /* HAVE_PCAP_VERSION */
117 #endif /* HAVE_LIBPCAP */
120 g_string_append(str, "with ");
121 g_string_sprintfa(str,
122 #ifdef GLIB_MAJOR_VERSION
123 "GLib %d.%d.%d,", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
126 "GLib (version unknown),");
130 g_string_append(str, " ");
131 break_point = str->len - 1;
133 g_string_append(str, "with WinPcap (version unknown)");
135 #ifdef HAVE_PCAP_VERSION
136 g_string_sprintfa(str, "with libpcap %s,", pcap_version);
137 #else /* HAVE_PCAP_VERSION */
138 g_string_append(str, "with libpcap (version unknown)");
139 #endif /* HAVE_PCAP_VERSION */
140 do_word_wrap(str, break_point);
142 #else /* HAVE_LIBPCAP */
143 g_string_append(str, " ");
144 break_point = str->len - 1;
146 g_string_append(str, "without WinPcap,");
148 g_string_append(str, "without libpcap,");
150 do_word_wrap(str, break_point);
151 #endif /* HAVE_LIBPCAP */
153 g_string_append(str, " ");
154 break_point = str->len - 1;
156 g_string_append(str, "with libz ");
158 g_string_append(str, ZLIB_VERSION);
159 #else /* ZLIB_VERSION */
160 g_string_append(str, "(version unknown)");
161 #endif /* ZLIB_VERSION */
162 #else /* HAVE_LIBZ */
163 g_string_append(str, "without libz");
164 #endif /* HAVE_LIBZ */
165 g_string_append(str, ",");
166 do_word_wrap(str, break_point);
168 /* Oh, this is pretty. */
169 /* Oh, ha. you think that was pretty. Try this:! --Wes */
170 g_string_append(str, " ");
171 break_point = str->len - 1;
172 #ifdef HAVE_SOME_SNMP
175 g_string_append(str, "with UCD-SNMP ");
176 g_string_append(str, VersionInfo);
177 #endif /* HAVE_UCD_SNMP */
180 g_string_append(str, "with Net-SNMP ");
181 g_string_append(str, netsnmp_get_version());
182 #endif /* HAVE_NET_SNMP */
184 #else /* no SNMP library */
185 g_string_append(str, "without UCD-SNMP or Net-SNMP");
186 #endif /* HAVE_SOME_SNMP */
187 g_string_append(str, ",");
188 do_word_wrap(str, break_point);
190 g_string_append(str, " ");
191 break_point = str->len - 1;
193 g_string_append(str, "with ADNS");
195 g_string_append(str, "without ADNS");
196 #endif /* HAVE_GNU_ADNS */
197 do_word_wrap(str, break_point);
201 * Get various library run-time versions, and the OS version, and append
202 * them to the specified GString.
205 get_runtime_version_info(GString *str)
209 #elif defined(HAVE_SYS_UTSNAME_H)
216 * On Windows, we might have been compiled with WinPcap but
217 * might not have it loaded; indicate whether we have it or
220 * XXX - when versions of libcap and WinPcap with
221 * "pcap_lib_version()" are released, we should use it
225 g_string_sprintfa(str, "with WinPcap ");
227 g_string_append(str, "without WinPcap ");
229 #endif /* HAVE_LIBPCAP */
231 g_string_append(str, "on ");
233 info.dwOSVersionInfoSize = sizeof info;
234 if (!GetVersionEx(&info)) {
236 * XXX - get the failure reason.
238 g_string_append(str, "unknown Windows version");
241 switch (info.dwPlatformId) {
243 case VER_PLATFORM_WIN32s:
245 g_string_sprintfa(str, "Windows 3.1 with Win32s");
248 case VER_PLATFORM_WIN32_WINDOWS:
250 switch (info.dwMajorVersion) {
253 /* 3 cheers for Microsoft marketing! */
254 switch (info.dwMinorVersion) {
257 g_string_sprintfa(str, "Windows 95");
261 g_string_sprintfa(str, "Windows 98");
265 g_string_sprintfa(str, "Windows Me");
269 g_string_sprintfa(str, "Windows OT, unknown version %u.%u",
270 info.dwMajorVersion, info.dwMinorVersion);
276 g_string_sprintfa(str, "Windows OT, unknown version %u.%u",
277 info.dwMajorVersion, info.dwMinorVersion);
282 case VER_PLATFORM_WIN32_NT:
284 switch (info.dwMajorVersion) {
288 g_string_sprintfa(str, "Windows NT %u.%u",
289 info.dwMajorVersion, info.dwMinorVersion);
293 /* 3 cheers for Microsoft marketing! */
294 switch (info.dwMinorVersion) {
297 g_string_sprintfa(str, "Windows 2000");
301 g_string_sprintfa(str, "Windows XP");
305 g_string_sprintfa(str, "Windows Server 2003");
309 g_string_sprintfa(str, "Windows NT, unknown version %u.%u",
310 info.dwMajorVersion, info.dwMinorVersion);
316 g_string_sprintfa(str, "Windows NT, unknown version %u.%u",
317 info.dwMajorVersion, info.dwMinorVersion);
323 g_string_sprintfa(str, "Unknown Windows platform %u version %u.%u",
324 info.dwPlatformId, info.dwMajorVersion, info.dwMinorVersion);
327 if (info.szCSDVersion[0] != '\0')
328 g_string_sprintfa(str, " %s", info.szCSDVersion);
329 g_string_sprintfa(str, ", build %u", info.dwBuildNumber);
330 #elif defined(HAVE_SYS_UTSNAME_H)
332 * We have <sys/utsname.h>, so we assume we have "uname()".
334 if (uname(&name) < 0) {
335 g_string_sprintfa(str, "unknown OS version (uname failed - %s)",
340 if (strcmp(name.sysname, "AIX") == 0) {
342 * Yay, IBM! Thanks for doing something different
343 * from most of the other UNIXes out there, and
344 * making "name.version" apparently be the major
345 * version number and "name.release" be the minor
348 g_string_sprintfa(str, "%s %s.%s", name.sysname, name.version,
352 * XXX - get "version" on any other platforms?
354 * On Digital/Tru65 UNIX, it's something unknown.
355 * On Solaris, it's some kind of build information.
356 * On HP-UX, it appears to be some sort of subrevision
359 g_string_sprintfa(str, "%s %s", name.sysname, name.release);
362 g_string_append(str, "an unknown OS");
367 * Collect command-line arguments as a string consisting of the arguments,
368 * separated by spaces.
371 get_args_as_string(int argc, char **argv, int optind)
378 * Find out how long the string will be.
381 for (i = optind; i < argc; i++) {
382 len += strlen(argv[i]);
383 len++; /* space, or '\0' if this is the last argument */
387 * Allocate the buffer for the string.
389 argstring = g_malloc(len);
392 * Now construct the string.
394 strcpy(argstring, "");
397 strcat(argstring, argv[i]);
401 strcat(argstring, " ");
407 setup_tmpdir(char *dir)
409 int len = strlen(dir);
412 /* Append slash if necessary */
413 if (dir[len - 1] == '/') {
417 newdir = g_malloc(len + 2);
425 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
427 static const char suffix[] = "XXXXXXXXXX";
428 int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
432 if (namebuflen < namelen) {
433 /* Stick in a truncated name, so that if this error is
434 reported with the file name, you at least get
436 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
437 errno = ENAMETOOLONG;
440 strcpy(namebuf, dir);
441 strcat(namebuf, pfx);
442 strcat(namebuf, suffix);
444 /* The Single UNIX Specification doesn't say that "mkstemp()"
445 creates the temporary file with mode rw-------, so we
446 won't assume that all UNIXes will do so; instead, we set
447 the umask to 0077 to take away all group and other
448 permissions, attempt to create the file, and then put
450 old_umask = umask(0077);
451 tmp_fd = mkstemp(namebuf);
456 static char *tmpdir = NULL;
458 static char *temp = NULL;
460 static char *E_tmpdir;
463 #define P_tmpdir "/var/tmp"
467 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
471 static gboolean initialized;
474 if ((dir = getenv("TMPDIR")) != NULL)
475 tmpdir = setup_tmpdir(dir);
477 if ((dir = getenv("TEMP")) != NULL)
478 temp = setup_tmpdir(dir);
481 E_tmpdir = setup_tmpdir(P_tmpdir);
485 if (tmpdir != NULL) {
486 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
493 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
499 fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
503 return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
506 /* ASCII/EBCDIC conversion tables from
507 * http://www.room42.com/store/computer_center/code_tables.shtml
510 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
511 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
512 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
513 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
514 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
515 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
516 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
517 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
518 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
519 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
520 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
521 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
522 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
523 0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
524 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
525 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
526 0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
527 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
528 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
529 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
530 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
531 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
532 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
533 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
534 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
535 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
536 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
537 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
538 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
539 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
540 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
541 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
542 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
546 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
553 for (i = 0; i < bytes; i++, bufptr++) {
554 *bufptr = ASCII_translate_EBCDIC[*bufptr];
559 ASCII_to_EBCDIC1(guint8 c)
561 return ASCII_translate_EBCDIC[c];
565 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
566 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
567 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
568 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
569 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
570 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
571 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
572 0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
573 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
574 0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
575 0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
576 0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
577 0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
578 0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
579 0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
580 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
581 0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
582 0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
583 0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
584 0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
585 0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
586 0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
587 0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
588 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
589 0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
590 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
591 0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
592 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
593 0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
594 0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
595 0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
596 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
597 0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
601 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
608 for (i = 0; i < bytes; i++, bufptr++) {
609 *bufptr = EBCDIC_translate_ASCII[*bufptr];
614 EBCDIC_to_ASCII1(guint8 c)
616 return EBCDIC_translate_ASCII[c];
619 /* Compute the difference between two seconds/microseconds time stamps. */
621 compute_timestamp_diff(gint *diffsec, gint *diffusec,
622 guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
625 /* The seconds part of the first time is the same as the seconds
626 part of the second time, so if the microseconds part of the first
627 time is less than the microseconds part of the second time, the
628 first time is before the second time. The microseconds part of
629 the delta should just be the difference between the microseconds
630 part of the first time and the microseconds part of the second
631 time; don't adjust the seconds part of the delta, as it's OK if
632 the microseconds part is negative. */
634 *diffsec = sec1 - sec2;
635 *diffusec = usec1 - usec2;
636 } else if (sec1 <= sec2) {
637 /* The seconds part of the first time is less than the seconds part
638 of the second time, so the first time is before the second time.
640 Both the "seconds" and "microseconds" value of the delta
641 should have the same sign, so if the difference between the
642 microseconds values would be *positive*, subtract 1,000,000
643 from it, and add one to the seconds value. */
644 *diffsec = sec1 - sec2;
645 if (usec2 >= usec1) {
646 *diffusec = usec1 - usec2;
648 *diffusec = (usec1 - 1000000) - usec2;
652 /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
653 *diffsec = sec1 - sec2;
654 if (usec2 <= usec1) {
655 *diffusec = usec1 - usec2;
657 *diffusec = (usec1 + 1000000) - usec2;
663 /* Decode a base64 string in-place - simple and slow algorithm.
664 Return length of result. Taken from rproxy/librsync/base64.c by
667 size_t base64_decode(char *s)
669 static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
670 int bit_offset, byte_offset, idx, i, n;
671 unsigned char *d = (unsigned char *)s;
676 while (*s && (p=strchr(b64, *s))) {
677 idx = (int)(p - b64);
678 byte_offset = (i*6)/8;
679 bit_offset = (i*6)%8;
680 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
681 if (bit_offset < 3) {
682 d[byte_offset] |= (idx << (2-bit_offset));
685 d[byte_offset] |= (idx >> (bit_offset-2));
686 d[byte_offset+1] = 0;
687 d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;