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