If we have <windows.h>, we need to include it to declare OSVERSIONINFO.
[obnox/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id: util.c,v 1.59 2003/03/08 11:15:49 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <errno.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #ifdef HAVE_WINDOWS_H
41 #include <windows.h>
42 #endif
43
44 #ifdef HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47
48 #ifdef NEED_SNPRINTF_H
49 # include "snprintf.h"
50 #endif
51
52 #ifdef NEED_MKSTEMP
53 #include "mkstemp.h"
54 #endif
55
56 #ifdef HAVE_IO_H
57 #include <io.h>
58 typedef int mode_t;     /* for win32 */
59 #endif
60
61 #ifdef HAVE_LIBZ
62 #include <zlib.h>       /* to get the libz version number */
63 #endif
64
65 #ifdef HAVE_SOME_SNMP
66
67 #ifdef HAVE_NET_SNMP
68 #include <net-snmp/version.h>
69 #endif /* HAVE_NET_SNMP */
70
71 #ifdef HAVE_UCD_SNMP
72 #include <ucd-snmp/version.h>
73 #endif /* HAVE_UCD_SNMP */
74
75 #endif /* HAVE_SOME_SNMP */
76
77 #ifdef HAVE_SYS_UTSNAME_H
78 #include <sys/utsname.h>
79 #endif
80
81 #include "util.h"
82
83 /*
84  * Get various library version and the OS version and append them to
85  * the specified GString.
86  */
87 void
88 get_version_info(GString *str)
89 {
90 #ifdef HAVE_LIBPCAP
91 #ifdef HAVE_PCAP_VERSION
92         extern char pcap_version[];
93 #endif /* HAVE_PCAP_VERSION */
94 #endif /* HAVE_LIBPCAP */
95 #if defined(WIN32)
96         OSVERSIONINFO info;
97 #elif defined(HAVE_SYS_UTSNAME_H)
98         struct utsname name;
99 #endif
100
101         g_string_append(str, "with ");
102         g_string_sprintfa(str,
103 #ifdef GLIB_MAJOR_VERSION
104             "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
105             GLIB_MICRO_VERSION);
106 #else
107             "GLib (version unknown)");
108 #endif
109
110 #ifdef HAVE_LIBPCAP
111         g_string_append(str, ", with libpcap ");
112 #ifdef HAVE_PCAP_VERSION
113         g_string_append(str, pcap_version);
114 #else /* HAVE_PCAP_VERSION */
115         g_string_append(str, "(version unknown)");
116 #endif /* HAVE_PCAP_VERSION */
117 #else /* HAVE_LIBPCAP */
118         g_string_append(str, "without libpcap");
119 #endif /* HAVE_LIBPCAP */
120
121 #ifdef HAVE_LIBZ
122         g_string_append(str, ", with libz ");
123 #ifdef ZLIB_VERSION
124         g_string_append(str, ZLIB_VERSION);
125 #else /* ZLIB_VERSION */
126         g_string_append(str, "(version unknown)");
127 #endif /* ZLIB_VERSION */
128 #else /* HAVE_LIBZ */
129         g_string_append(str, ", without libz");
130 #endif /* HAVE_LIBZ */
131
132 /* Oh, this is pretty. */
133 /* Oh, ha.  you think that was pretty.  Try this:! --Wes */
134 #ifdef HAVE_SOME_SNMP
135
136 #ifdef HAVE_UCD_SNMP
137         g_string_append(str, ", with UCD-SNMP ");
138         g_string_append(str, VersionInfo);
139 #endif /* HAVE_UCD_SNMP */
140
141 #ifdef HAVE_NET_SNMP
142         g_string_append(str, ", with Net-SNMP ");
143         g_string_append(str, netsnmp_get_version());
144 #endif /* HAVE_NET_SNMP */
145
146 #else /* no SNMP library */
147         g_string_append(str, ", without UCD-SNMP or Net-SNMP");
148 #endif /* HAVE_SOME_SNMP */
149
150         g_string_append(str, ", running on ");
151 #if defined(WIN32)
152         info.dwOSVersionInfoSize = sizeof info;
153         if (!GetVersionEx(&info)) {
154                 /*
155                  * XXX - get the failure reason.
156                  */
157                 g_string_append(str, "unknown Windows version");
158                 return;
159         }
160         switch (info.dwPlatformId) {
161
162         case VER_PLATFORM_WIN32s:
163                 /* Shyeah, right. */
164                 g_string_sprintfa(str, "Windows 3.1 with Win32s");
165                 break;
166
167         case VER_PLATFORM_WIN32_WINDOWS:
168                 /* Windows OT */
169                 switch (info.dwMajorVersion) {
170
171                 case 4:
172                         /* 3 cheers for Microsoft marketing! */
173                         switch (info.dwMinorVersion) {
174
175                         case 0:
176                                 g_string_sprintfa(str, "Windows 95");
177                                 break;
178
179                         case 10:
180                                 g_string_sprintfa(str, "Windows 98");
181                                 break;
182
183                         case 90:
184                                 g_string_sprintfa(str, "Windows Me");
185                                 break;
186
187                         default:
188                                 g_string_sprintfa(str, "Windows OT, unknown version %u.%u",
189                                     info.dwMajorVersion, info.dwMinorVersion);
190                                 break;
191                         }
192                         break;
193
194                 default:
195                         g_string_sprintfa(str, "Windows OT, unknown version %u.%u",
196                             info.dwMajorVersion, info.dwMinorVersion);
197                         break;
198                 }
199                 break;
200
201         case VER_PLATFORM_WIN32_NT:
202                 /* Windows NT */
203                 switch (info.dwMajorVersion) {
204
205                 case 3:
206                 case 4:
207                         g_string_sprintfa(str, "Windows NT %u.%u",
208                             info.dwMajorVersion, info.dwMinorVersion);
209                         break;
210
211                 case 5:
212                         /* 3 cheers for Microsoft marketing! */
213                         switch (info.dwMinorVersion) {
214
215                         case 0:
216                                 g_string_sprintfa(str, "Windows 2000");
217                                 break;
218
219                         case 1:
220                                 g_string_sprintfa(str, "Windows XP");
221                                 break;
222
223                         case 2:
224                                 g_string_sprintfa(str, "Windows Server 2003");
225                                 break;
226
227                         default:
228                                 g_string_sprintfa(str, "Windows NT, unknown version %u.%u",
229                                     info.dwMajorVersion, info.dwMinorVersion);
230                                 break;
231                         }
232                         break;
233
234                 default:
235                         g_string_sprintfa(str, "Windows NT, unknown version %u.%u",
236                             info.dwMajorVersion, info.dwMinorVersion);
237                         break;
238                 }
239                 break;
240
241         default:
242                 g_string_sprintfa(str, "Unknown Windows platform %u version %u.%u",
243                     info.dwPlatformId, info.dwMajorVersion, info.dwMinorVersion);
244                 break;
245         }
246         if (info.szCSDVersion[0] != '\0')
247                 g_string_sprintfa(str, " %s", info.szCSDVersion);
248         g_string_sprintfa(str, ", build %u", info.dwBuildNumber);
249 #elif defined(HAVE_SYS_UTSNAME_H)
250         /*
251          * We have <sys/utsname.h>, so we assume we have "uname()".
252          */
253         if (uname(&name) < 0) {
254                 g_string_sprintfa(str, "unknown OS version (uname failed - %s)",
255                     strerror(errno));
256                 return;
257         }
258
259         if (strcmp(name.sysname, "AIX") == 0) {
260                 /*
261                  * Yay, IBM!  Thanks for doing something different
262                  * from most of the other UNIXes out there, and
263                  * making "name.version" apparently be the major
264                  * version number and "name.release" be the minor
265                  * version number.
266                  */
267                 g_string_sprintfa(str, "%s %s.%s", name.sysname, name.version,
268                     name.release);
269         } else {
270                 /*
271                  * XXX - get "version" on any other platforms?
272                  *
273                  * On Digital/Tru65 UNIX, it's something unknown.
274                  * On Solaris, it's some kind of build information.
275                  * On HP-UX, it appears to be some sort of subrevision
276                  * thing.
277                  */
278                 g_string_sprintfa(str, "%s %s", name.sysname, name.release);
279         }
280 #else
281         g_string_append("an unknown OS");
282 #endif
283 }
284
285 /*
286  * Collect command-line arguments as a string consisting of the arguments,
287  * separated by spaces.
288  */
289 char *
290 get_args_as_string(int argc, char **argv, int optind)
291 {
292         int len;
293         int i;
294         char *argstring;
295
296         /*
297          * Find out how long the string will be.
298          */
299         len = 0;
300         for (i = optind; i < argc; i++) {
301                 len += strlen(argv[i]);
302                 len++;  /* space, or '\0' if this is the last argument */
303         }
304
305         /*
306          * Allocate the buffer for the string.
307          */
308         argstring = g_malloc(len);
309
310         /*
311          * Now construct the string.
312          */
313         strcpy(argstring, "");
314         i = optind;
315         for (;;) {
316                 strcat(argstring, argv[i]);
317                 i++;
318                 if (i == argc)
319                         break;
320                 strcat(argstring, " ");
321         }
322         return argstring;
323 }
324
325 static char *
326 setup_tmpdir(char *dir)
327 {
328         int len = strlen(dir);
329         char *newdir;
330
331         /* Append slash if necessary */
332         if (dir[len - 1] == '/') {
333                 newdir = dir;
334         }
335         else {
336                 newdir = g_malloc(len + 2);
337                 strcpy(newdir, dir);
338                 strcat(newdir, "/");
339         }
340         return newdir;
341 }
342
343 static int
344 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
345 {
346         static const char suffix[] = "XXXXXXXXXX";
347         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
348         mode_t old_umask;
349         int tmp_fd;
350
351         if (namebuflen < namelen) {
352                 /* Stick in a truncated name, so that if this error is
353                    reported with the file name, you at least get
354                    something. */
355                 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
356                 errno = ENAMETOOLONG;
357                 return -1;
358         }
359         strcpy(namebuf, dir);
360         strcat(namebuf, pfx);
361         strcat(namebuf, suffix);
362
363         /* The Single UNIX Specification doesn't say that "mkstemp()"
364            creates the temporary file with mode rw-------, so we
365            won't assume that all UNIXes will do so; instead, we set
366            the umask to 0077 to take away all group and other
367            permissions, attempt to create the file, and then put
368            the umask back. */
369         old_umask = umask(0077);
370         tmp_fd = mkstemp(namebuf);
371         umask(old_umask);
372         return tmp_fd;
373 }
374
375 static char *tmpdir = NULL;
376 #ifdef WIN32
377 static char *temp = NULL;
378 #endif
379 static char *E_tmpdir;
380
381 #ifndef P_tmpdir
382 #define P_tmpdir "/var/tmp"
383 #endif
384
385 int
386 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
387 {
388         char *dir;
389         int fd;
390         static gboolean initialized;
391
392         if (!initialized) {
393                 if ((dir = getenv("TMPDIR")) != NULL)
394                         tmpdir = setup_tmpdir(dir);
395 #ifdef WIN32
396                 if ((dir = getenv("TEMP")) != NULL)
397                         temp = setup_tmpdir(dir);
398 #endif
399
400                 E_tmpdir = setup_tmpdir(P_tmpdir);
401                 initialized = TRUE;
402         }
403
404         if (tmpdir != NULL) {
405                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
406                 if (fd != -1)
407                         return fd;
408         }
409
410 #ifdef WIN32
411         if (temp != NULL) {
412                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
413                 if (fd != -1)
414                         return fd;
415         }
416 #endif
417
418         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
419         if (fd != -1)
420                 return fd;
421
422         return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
423 }
424
425 /* ASCII/EBCDIC conversion tables from
426  * http://www.room42.com/store/computer_center/code_tables.shtml
427  */
428 #if 0
429 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
430     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
431     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
432     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
433     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
434     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
435     0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
436     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
437     0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
438     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
439     0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
440     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
441     0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
442     0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
443     0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
444     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
445     0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
446     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
447     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
448     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
449     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
450     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
451     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
452     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
453     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
454     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
455     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
456     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
457     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
458     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
459     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
460     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
461     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
462 };
463
464 void
465 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
466 {
467         guint   i;
468         guint8  *bufptr;
469
470         bufptr = buf;
471
472         for (i = 0; i < bytes; i++, bufptr++) {
473                 *bufptr = ASCII_translate_EBCDIC[*bufptr];
474         }
475 }
476
477 guint8
478 ASCII_to_EBCDIC1(guint8 c)
479 {
480         return ASCII_translate_EBCDIC[c];
481 }
482 #endif
483
484 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
485     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
486     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
487     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
488     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
489     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
490     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
491     0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
492     0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
493     0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
494     0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
495     0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
496     0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
497     0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
498     0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
499     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
500     0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
501     0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
502     0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
503     0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
504     0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
505     0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
506     0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
507     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
508     0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
509     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
510     0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
511     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
512     0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
513     0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
514     0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
515     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
516     0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
517 };
518
519 void
520 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
521 {
522         guint   i;
523         guint8  *bufptr;
524
525         bufptr = buf;
526
527         for (i = 0; i < bytes; i++, bufptr++) {
528                 *bufptr = EBCDIC_translate_ASCII[*bufptr];
529         }
530 }
531
532 guint8
533 EBCDIC_to_ASCII1(guint8 c)
534 {
535         return EBCDIC_translate_ASCII[c];
536 }
537
538 /* Compute the difference between two seconds/microseconds time stamps. */
539 void
540 compute_timestamp_diff(gint *diffsec, gint *diffusec,
541         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
542 {
543   if (sec1 == sec2) {
544     /* The seconds part of the first time is the same as the seconds
545        part of the second time, so if the microseconds part of the first
546        time is less than the microseconds part of the second time, the
547        first time is before the second time.  The microseconds part of
548        the delta should just be the difference between the microseconds
549        part of the first time and the microseconds part of the second
550        time; don't adjust the seconds part of the delta, as it's OK if
551        the microseconds part is negative. */
552
553     *diffsec = sec1 - sec2;
554     *diffusec = usec1 - usec2;
555   } else if (sec1 <= sec2) {
556     /* The seconds part of the first time is less than the seconds part
557        of the second time, so the first time is before the second time.
558
559        Both the "seconds" and "microseconds" value of the delta
560        should have the same sign, so if the difference between the
561        microseconds values would be *positive*, subtract 1,000,000
562        from it, and add one to the seconds value. */
563     *diffsec = sec1 - sec2;
564     if (usec2 >= usec1) {
565       *diffusec = usec1 - usec2;
566     } else {
567       *diffusec = (usec1 - 1000000) - usec2;
568       (*diffsec)++;
569     }
570   } else {
571     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
572     *diffsec = sec1 - sec2;
573     if (usec2 <= usec1) {
574       *diffusec = usec1 - usec2;
575     } else {
576       *diffusec = (usec1 + 1000000) - usec2;
577       (*diffsec)--;
578     }
579   }
580 }