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