I Noticed a crash when registering a tap with filter during handoff (that's when...
[metze/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id$
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 #include "file_util.h"
41
42 #include <epan/address.h>
43 #include <epan/addr_resolv.h>
44
45 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6)
46 #include <glib/gstdio.h>        /* available since GLib 2.6 only! */
47
48 /* GLib2.6 or above, using new wrapper functions */
49 #define eth_mkstemp g_mkstemp
50 #else
51 #define eth_mkstemp mkstemp
52 #endif
53
54 /*
55  * This has to come after the include of <pcap.h>, as the include of
56  * <pcap.h> might cause <winsock2.h> to be included, and if we've
57  * already included <winsock.h> as a result of including <windows.h>,
58  * we get a bunch of redefinitions.
59  */
60 #ifdef HAVE_WINDOWS_H
61 #include <windows.h>
62 #endif
63
64 #include "util.h"
65
66 /*
67  * Collect command-line arguments as a string consisting of the arguments,
68  * separated by spaces.
69  */
70 char *
71 get_args_as_string(int argc, char **argv, int optind)
72 {
73         int len;
74         int i;
75         char *argstring;
76
77         /*
78          * Find out how long the string will be.
79          */
80         len = 0;
81         for (i = optind; i < argc; i++) {
82                 len += strlen(argv[i]);
83                 len++;  /* space, or '\0' if this is the last argument */
84         }
85
86         /*
87          * Allocate the buffer for the string.
88          */
89         argstring = g_malloc(len);
90
91         /*
92          * Now construct the string.
93          */
94         strcpy(argstring, "");
95         i = optind;
96         for (;;) {
97                 strcat(argstring, argv[i]);
98                 i++;
99                 if (i == argc)
100                         break;
101                 strcat(argstring, " ");
102         }
103         return argstring;
104 }
105
106 static const char *
107 setup_tmpdir(const char *dir)
108 {
109         size_t len = strlen(dir);
110         char *newdir;
111
112         /* Append path separator if necessary */
113         if (len != 0 && dir[len - 1] == G_DIR_SEPARATOR) {
114                 return dir;
115         }
116         else {
117                 newdir = g_malloc(len + 2);
118                 strcpy(newdir, dir);
119                 strcat(newdir, G_DIR_SEPARATOR_S);
120                 return newdir;
121         }
122 }
123
124 static int
125 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
126 {
127         static const char suffix[] = "XXXXXXXXXX";
128         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
129         int old_umask;
130         int tmp_fd;
131
132         if (namebuflen < namelen) {
133                 /* Stick in a truncated name, so that if this error is
134                    reported with the file name, you at least get
135                    something. */
136                 g_snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
137                 errno = ENAMETOOLONG;
138                 return -1;
139         }
140         strcpy(namebuf, dir);
141         strcat(namebuf, pfx);
142         strcat(namebuf, suffix);
143
144         /* The Single UNIX Specification doesn't say that "mkstemp()"
145            creates the temporary file with mode rw-------, so we
146            won't assume that all UNIXes will do so; instead, we set
147            the umask to 0077 to take away all group and other
148            permissions, attempt to create the file, and then put
149            the umask back. */
150         old_umask = umask(0077);
151         tmp_fd = eth_mkstemp(namebuf);
152         umask(old_umask);
153         return tmp_fd;
154 }
155
156 static const char *tmpdir = NULL;
157 #ifdef _WIN32
158 static const char *temp = NULL;
159 #endif
160 static const char *E_tmpdir;
161
162 #ifndef P_tmpdir
163 #define P_tmpdir "/var/tmp"
164 #endif
165
166 int
167 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
168 {
169         char *dir;
170         int fd;
171         static gboolean initialized;
172
173         if (!initialized) {
174                 if ((dir = getenv("TMPDIR")) != NULL)
175                         tmpdir = setup_tmpdir(dir);
176 #ifdef _WIN32
177                 if ((dir = getenv("TEMP")) != NULL)
178                         temp = setup_tmpdir(dir);
179 #endif
180
181                 E_tmpdir = setup_tmpdir(P_tmpdir);
182                 initialized = TRUE;
183         }
184
185         if (tmpdir != NULL) {
186                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
187                 if (fd != -1)
188                         return fd;
189         }
190
191 #ifdef _WIN32
192         if (temp != NULL) {
193                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
194                 if (fd != -1)
195                         return fd;
196         }
197 #endif
198
199         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
200         if (fd != -1)
201                 return fd;
202
203         return try_tempfile(namebuf, namebuflen, G_DIR_SEPARATOR_S "tmp", pfx);
204 }
205
206 /* Compute the difference between two seconds/microseconds time stamps. */
207 void
208 compute_timestamp_diff(gint *diffsec, gint *diffusec,
209         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
210 {
211   if (sec1 == sec2) {
212     /* The seconds part of the first time is the same as the seconds
213        part of the second time, so if the microseconds part of the first
214        time is less than the microseconds part of the second time, the
215        first time is before the second time.  The microseconds part of
216        the delta should just be the difference between the microseconds
217        part of the first time and the microseconds part of the second
218        time; don't adjust the seconds part of the delta, as it's OK if
219        the microseconds part is negative. */
220
221     *diffsec = sec1 - sec2;
222     *diffusec = usec1 - usec2;
223   } else if (sec1 <= sec2) {
224     /* The seconds part of the first time is less than the seconds part
225        of the second time, so the first time is before the second time.
226
227        Both the "seconds" and "microseconds" value of the delta
228        should have the same sign, so if the difference between the
229        microseconds values would be *positive*, subtract 1,000,000
230        from it, and add one to the seconds value. */
231     *diffsec = sec1 - sec2;
232     if (usec2 >= usec1) {
233       *diffusec = usec1 - usec2;
234     } else {
235       *diffusec = (usec1 - 1000000) - usec2;
236       (*diffsec)++;
237     }
238   } else {
239     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
240     *diffsec = sec1 - sec2;
241     if (usec2 <= usec1) {
242       *diffusec = usec1 - usec2;
243     } else {
244       *diffusec = (usec1 + 1000000) - usec2;
245       (*diffsec)--;
246     }
247   }
248 }
249
250 /* Try to figure out if we're remotely connected, e.g. via ssh or
251    Terminal Server, and create a capture filter that matches aspects of the
252    connection.  We match the following environment variables:
253
254    SSH_CONNECTION (ssh): <remote IP> <remote port> <local IP> <local port>
255    SSH_CLIENT (ssh): <remote IP> <remote port> <local port>
256    REMOTEHOST (tcsh, others?): <remote name>
257    DISPLAY (x11): [remote name]:<display num>
258    CLIENTNAME (terminal server): <remote name>
259  */
260
261 const gchar *get_conn_cfilter(void) {
262         static GString *filter_str = NULL;
263         gchar *env, **tokens;
264
265         if (filter_str == NULL) {
266                 filter_str = g_string_new("");
267         }
268         if ((env = getenv("SSH_CONNECTION")) != NULL) {
269                 tokens = g_strsplit(env, " ", 4);
270                 if (tokens[3]) {
271                         g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
272                                                          "and tcp port %s and %s host %s)", tokens[1], host_ip_af(tokens[0]), tokens[0],
273                                 tokens[3], host_ip_af(tokens[2]), tokens[2]);
274                         return filter_str->str;
275                 }
276         } else if ((env = getenv("SSH_CLIENT")) != NULL) {
277                 tokens = g_strsplit(env, " ", 3);
278                 g_string_sprintf(filter_str, "not (tcp port %s and %s host %s "
279                         "and tcp port %s)", tokens[1], host_ip_af(tokens[0]), tokens[0], tokens[2]);
280                 return filter_str->str;
281         } else if ((env = getenv("REMOTEHOST")) != NULL) {
282                 if (strcasecmp(env, "localhost") == 0 || strcmp(env, "127.0.0.1") == 0) {
283                         return "";
284                 }
285                 g_string_sprintf(filter_str, "not %s host %s", host_ip_af(env), env);
286                 return filter_str->str;
287         } else if ((env = getenv("DISPLAY")) != NULL) {
288                 tokens = g_strsplit(env, ":", 2);
289                 if (tokens[0] && tokens[0][0] != 0) {
290                         if (strcasecmp(tokens[0], "localhost") == 0 ||
291                                         strcmp(tokens[0], "127.0.0.1") == 0) {
292                                 return "";
293                         }
294                         g_string_sprintf(filter_str, "not %s host %s",
295                                 host_ip_af(tokens[0]), tokens[0]);
296                         return filter_str->str;
297                 }
298         } else if ((env = getenv("CLIENTNAME")) != NULL) {
299                 g_string_sprintf(filter_str, "not tcp port 3389");
300                 return filter_str->str;
301         }
302         return "";
303 }