nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* filesystem.c |
2 | * Filesystem utility routines |
||
3 | * |
||
4 | * Wireshark - Network traffic analyzer |
||
5 | * By Gerald Combs <gerald@wireshark.org> |
||
6 | * Copyright 1998 Gerald Combs |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU General Public License |
||
10 | * as published by the Free Software Foundation; either version 2 |
||
11 | * of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * This program is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU General Public License |
||
19 | * along with this program; if not, write to the Free Software |
||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
21 | */ |
||
22 | |||
23 | #include <config.h> |
||
24 | |||
25 | /* |
||
26 | * Required with GNU libc to get dladdr(). |
||
27 | * We define it here because <dlfcn.h> apparently gets included by |
||
28 | * one of the headers we include below. |
||
29 | */ |
||
30 | #define _GNU_SOURCE |
||
31 | |||
32 | #include <stdio.h> |
||
33 | #include <stdlib.h> |
||
34 | #include <string.h> |
||
35 | #include <errno.h> |
||
36 | |||
37 | #include <glib.h> |
||
38 | |||
39 | #ifdef _WIN32 |
||
40 | #include <windows.h> |
||
41 | #include <tchar.h> |
||
42 | #include <shlobj.h> |
||
43 | #include <wsutil/unicode-utils.h> |
||
44 | #else /* _WIN32 */ |
||
45 | #ifdef __APPLE__ |
||
46 | #include <mach-o/dyld.h> |
||
47 | #endif |
||
48 | #ifdef __linux__ |
||
49 | #include <sys/utsname.h> |
||
50 | #endif |
||
51 | #ifdef __FreeBSD__ |
||
52 | #include <sys/types.h> |
||
53 | #include <sys/sysctl.h> |
||
54 | #endif |
||
55 | #ifdef HAVE_DLADDR |
||
56 | #include <dlfcn.h> |
||
57 | #endif |
||
58 | #include <pwd.h> |
||
59 | #endif /* _WIN32 */ |
||
60 | |||
61 | #include "filesystem.h" |
||
62 | #include <wsutil/report_err.h> |
||
63 | #include <wsutil/privileges.h> |
||
64 | #include <wsutil/file_util.h> |
||
65 | #include <wsutil/utf8_entities.h> |
||
66 | |||
67 | #include <wiretap/wtap.h> /* for WTAP_ERR_SHORT_WRITE */ |
||
68 | |||
69 | #define PROFILES_DIR "profiles" |
||
70 | #define PLUGINS_DIR_NAME "plugins" |
||
71 | |||
72 | char *persconffile_dir = NULL; |
||
73 | char *persdatafile_dir = NULL; |
||
74 | char *persconfprofile = NULL; |
||
75 | |||
76 | static gboolean do_store_persconffiles = FALSE; |
||
77 | static GHashTable *profile_files = NULL; |
||
78 | |||
79 | /* |
||
80 | * Given a pathname, return a pointer to the last pathname separator |
||
81 | * character in the pathname, or NULL if the pathname contains no |
||
82 | * separators. |
||
83 | */ |
||
84 | char * |
||
85 | find_last_pathname_separator(const char *path) |
||
86 | { |
||
87 | char *separator; |
||
88 | |||
89 | #ifdef _WIN32 |
||
90 | char c; |
||
91 | |||
92 | /* |
||
93 | * We have to scan for '\' or '/'. |
||
94 | * Get to the end of the string. |
||
95 | */ |
||
96 | separator = strchr(path, '\0'); /* points to ending '\0' */ |
||
97 | while (separator > path) { |
||
98 | c = *--separator; |
||
99 | if (c == '\\' || c == '/') |
||
100 | return separator; /* found it */ |
||
101 | } |
||
102 | |||
103 | /* |
||
104 | * OK, we didn't find any, so no directories - but there might |
||
105 | * be a drive letter.... |
||
106 | */ |
||
107 | return strchr(path, ':'); |
||
108 | #else |
||
109 | separator = strrchr(path, '/'); |
||
110 | return separator; |
||
111 | #endif |
||
112 | } |
||
113 | |||
114 | /* |
||
115 | * Given a pathname, return the last component. |
||
116 | */ |
||
117 | const char * |
||
118 | get_basename(const char *path) |
||
119 | { |
||
120 | const char *filename; |
||
121 | |||
122 | g_assert(path != NULL); |
||
123 | filename = find_last_pathname_separator(path); |
||
124 | if (filename == NULL) { |
||
125 | /* |
||
126 | * There're no directories, drive letters, etc. in the |
||
127 | * name; the pathname *is* the file name. |
||
128 | */ |
||
129 | filename = path; |
||
130 | } else { |
||
131 | /* |
||
132 | * Skip past the pathname or drive letter separator. |
||
133 | */ |
||
134 | filename++; |
||
135 | } |
||
136 | return filename; |
||
137 | } |
||
138 | |||
139 | /* |
||
140 | * Given a pathname, return a string containing everything but the |
||
141 | * last component. NOTE: this overwrites the pathname handed into |
||
142 | * it.... |
||
143 | */ |
||
144 | char * |
||
145 | get_dirname(char *path) |
||
146 | { |
||
147 | char *separator; |
||
148 | |||
149 | g_assert(path != NULL); |
||
150 | separator = find_last_pathname_separator(path); |
||
151 | if (separator == NULL) { |
||
152 | /* |
||
153 | * There're no directories, drive letters, etc. in the |
||
154 | * name; there is no directory path to return. |
||
155 | */ |
||
156 | return NULL; |
||
157 | } |
||
158 | |||
159 | /* |
||
160 | * Get rid of the last pathname separator and the final file |
||
161 | * name following it. |
||
162 | */ |
||
163 | *separator = '\0'; |
||
164 | |||
165 | /* |
||
166 | * "path" now contains the pathname of the directory containing |
||
167 | * the file/directory to which it referred. |
||
168 | */ |
||
169 | return path; |
||
170 | } |
||
171 | |||
172 | /* |
||
173 | * Given a pathname, return: |
||
174 | * |
||
175 | * the errno, if an attempt to "stat()" the file fails; |
||
176 | * |
||
177 | * EISDIR, if the attempt succeeded and the file turned out |
||
178 | * to be a directory; |
||
179 | * |
||
180 | * 0, if the attempt succeeded and the file turned out not |
||
181 | * to be a directory. |
||
182 | */ |
||
183 | |||
184 | int |
||
185 | test_for_directory(const char *path) |
||
186 | { |
||
187 | ws_statb64 statb; |
||
188 | |||
189 | if (ws_stat64(path, &statb) < 0) |
||
190 | return errno; |
||
191 | |||
192 | if (S_ISDIR(statb.st_mode)) |
||
193 | return EISDIR; |
||
194 | else |
||
195 | return 0; |
||
196 | } |
||
197 | |||
198 | int |
||
199 | test_for_fifo(const char *path) |
||
200 | { |
||
201 | ws_statb64 statb; |
||
202 | |||
203 | if (ws_stat64(path, &statb) < 0) |
||
204 | return errno; |
||
205 | |||
206 | if (S_ISFIFO(statb.st_mode)) |
||
207 | return ESPIPE; |
||
208 | else |
||
209 | return 0; |
||
210 | } |
||
211 | |||
212 | /* |
||
213 | * Directory from which the executable came. |
||
214 | */ |
||
215 | static char *progfile_dir; |
||
216 | |||
217 | #ifdef __APPLE__ |
||
218 | /* |
||
219 | * Directory of the application bundle in which we're contained, |
||
220 | * if we're contained in an application bundle. Otherwise, NULL. |
||
221 | * |
||
222 | * Note: Table 2-5 "Subdirectories of the Contents directory" of |
||
223 | * |
||
224 | * https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1 |
||
225 | * |
||
226 | * says that the "Frameworks" directory |
||
227 | * |
||
228 | * Contains any private shared libraries and frameworks used by the |
||
229 | * executable. The frameworks in this directory are revision-locked |
||
230 | * to the application and cannot be superseded by any other, even |
||
231 | * newer, versions that may be available to the operating system. In |
||
232 | * other words, the frameworks included in this directory take precedence |
||
233 | * over any other similarly named frameworks found in other parts of |
||
234 | * the operating system. For information on how to add private |
||
235 | * frameworks to your application bundle, see Framework Programming Guide. |
||
236 | * |
||
237 | * so if we were to ship with any frameworks (e.g. Qt) we should |
||
238 | * perhaps put them in a Frameworks directory rather than under |
||
239 | * Resources. |
||
240 | * |
||
241 | * It also says that the "PlugIns" directory |
||
242 | * |
||
243 | * Contains loadable bundles that extend the basic features of your |
||
244 | * application. You use this directory to include code modules that |
||
245 | * must be loaded into your applicationbs process space in order to |
||
246 | * be used. You would not use this directory to store standalone |
||
247 | * executables. |
||
248 | * |
||
249 | * Our plugins are just raw .so/.dylib files; I don't know whether by |
||
250 | * "bundles" they mean application bundles (i.e., directory hierarchies) |
||
251 | * or just "bundles" in the Mach-O sense (which are an image type that |
||
252 | * can be loaded with dlopen() but not linked as libraries; our plugins |
||
253 | * are, I think, built as dylibs and can be loaded either way). |
||
254 | * |
||
255 | * And it says that the "SharedSupport" directory |
||
256 | * |
||
257 | * Contains additional non-critical resources that do not impact the |
||
258 | * ability of the application to run. You might use this directory to |
||
259 | * include things like document templates, clip art, and tutorials |
||
260 | * that your application expects to be present but that do not affect |
||
261 | * the ability of your application to run. |
||
262 | * |
||
263 | * I don't think I'd put the files that currently go under Resources/share |
||
264 | * into that category; they're not, for example, sample Lua scripts that |
||
265 | * don't actually get run by Wireshark, they're configuration/data files |
||
266 | * for Wireshark whose absence might not prevent Wireshark from running |
||
267 | * but that would affect how it behaves when run. |
||
268 | */ |
||
269 | static char *appbundle_dir; |
||
270 | #endif |
||
271 | |||
272 | /* |
||
273 | * TRUE if we're running from the build directory and we aren't running |
||
274 | * with special privileges. |
||
275 | */ |
||
276 | static gboolean running_in_build_directory_flag = FALSE; |
||
277 | |||
278 | #ifndef _WIN32 |
||
279 | /* |
||
280 | * Get the pathname of the executable using various platform- |
||
281 | * dependent mechanisms for various UN*Xes. |
||
282 | * |
||
283 | * These calls all should return something independent of the argv[0] |
||
284 | * passed to the program, so it shouldn't be fooled by an argv[0] |
||
285 | * that doesn't match the executable path. |
||
286 | * |
||
287 | * Sadly, not all UN*Xes necessarily have dladdr(), and those that |
||
288 | * do don't necessarily have dladdr(main) return information about |
||
289 | * the executable image, and those that do aren't necessarily running |
||
290 | * on a platform wherein the executable image can get its own path |
||
291 | * from the kernel (either by a call or by it being handed to it along |
||
292 | * with argv[] and the environment), and those that can don't |
||
293 | * necessarily use that to supply the path you get from dladdr(main), |
||
294 | * so we try this first and, if that fails, use dladdr(main) if |
||
295 | * available. |
||
296 | * |
||
297 | * In particular, some dynamic linkers supply a dladdr() such that |
||
298 | * dladdr(main) just returns something derived from argv[0], so |
||
299 | * just using dladdr(main) is the wrong thing to do if there's |
||
300 | * another mechanism that can get you a more reliable version of |
||
301 | * the executable path. |
||
302 | * |
||
303 | * However, at least in newer versions of DragonFly BSD, the dynamic |
||
304 | * linker *does* get it from the aux vector passed to the program |
||
305 | * by the kernel, readlink /proc/curproc/file - which came first? |
||
306 | * |
||
307 | * On OpenBSD, dladdr(main) returns a value derived from argv[0], |
||
308 | * and there doesn't appear to be any way to get the executable path |
||
309 | * from the kernel, so we're out of luck there. |
||
310 | * |
||
311 | * So, on platforms where some versions have a version of dladdr() |
||
312 | * that gives an argv[0]-based path and that also have a mechanism |
||
313 | * to get a more reliable version of the path, we try that. On |
||
314 | * other platforms, we return NULL. If our caller gets back a NULL |
||
315 | * from us, it falls back on dladdr(main) if dladdr() is available, |
||
316 | * and if that fails or is unavailable, it falls back on processing |
||
317 | * argv[0] itself. |
||
318 | * |
||
319 | * This is not guaranteed to return an absolute path; if it doesn't, |
||
320 | * our caller must prepend the current directory if it's a path. |
||
321 | * |
||
322 | * This is not guaranteed to return the "real path"; it might return |
||
323 | * something with symbolic links in the path. Our caller must |
||
324 | * use realpath() if they want the real thing, but that's also true of |
||
325 | * something obtained by looking at argv[0]. |
||
326 | */ |
||
327 | static const char * |
||
328 | get_executable_path(void) |
||
329 | { |
||
330 | #if defined(__APPLE__) |
||
331 | char *executable_path; |
||
332 | uint32_t path_buf_size; |
||
333 | |||
334 | path_buf_size = PATH_MAX; |
||
335 | executable_path = (char *)g_malloc(path_buf_size); |
||
336 | if (_NSGetExecutablePath(executable_path, &path_buf_size) == -1) { |
||
337 | executable_path = (char *)g_realloc(executable_path, path_buf_size); |
||
338 | if (_NSGetExecutablePath(executable_path, &path_buf_size) == -1) |
||
339 | return NULL; |
||
340 | } |
||
341 | return executable_path; |
||
342 | #elif defined(__linux__) |
||
343 | /* |
||
344 | * In older versions of GNU libc's dynamic linker, as used on Linux, |
||
345 | * dladdr(main) supplies a path based on argv[0], so we use |
||
346 | * /proc/self/exe instead; there are Linux distributions with |
||
347 | * kernels that support /proc/self/exe and those older versions |
||
348 | * of the dynamic linker, and this will get a better answer on |
||
349 | * those versions. |
||
350 | * |
||
351 | * It only works on Linux 2.2 or later, so we just give up on |
||
352 | * earlier versions. |
||
353 | * |
||
354 | * XXX - are there OS versions that support "exe" but not "self"? |
||
355 | */ |
||
356 | struct utsname name; |
||
357 | static char executable_path[PATH_MAX + 1]; |
||
358 | ssize_t r; |
||
359 | |||
360 | if (uname(&name) == -1) |
||
361 | return NULL; |
||
362 | if (strncmp(name.release, "1.", 2) == 0) |
||
363 | return NULL; /* Linux 1.x */ |
||
364 | if (strcmp(name.release, "2.0") == 0 || |
||
365 | strncmp(name.release, "2.0.", 4) == 0 || |
||
366 | strcmp(name.release, "2.1") == 0 || |
||
367 | strncmp(name.release, "2.1.", 4) == 0) |
||
368 | return NULL; /* Linux 2.0.x or 2.1.x */ |
||
369 | if ((r = readlink("/proc/self/exe", executable_path, PATH_MAX)) == -1) |
||
370 | return NULL; |
||
371 | executable_path[r] = '\0'; |
||
372 | return executable_path; |
||
373 | #elif defined(__FreeBSD__) && defined(KERN_PROC_PATHNAME) |
||
374 | /* |
||
375 | * In older versions of FreeBSD's dynamic linker, dladdr(main) |
||
376 | * supplies a path based on argv[0], so we use the KERN_PROC_PATHNAME |
||
377 | * sysctl instead; there are, I think, versions of FreeBSD |
||
378 | * that support the sysctl that have and those older versions |
||
379 | * of the dynamic linker, and this will get a better answer on |
||
380 | * those versions. |
||
381 | */ |
||
382 | int mib[4]; |
||
383 | char *executable_path; |
||
384 | size_t path_buf_size; |
||
385 | |||
386 | mib[0] = CTL_KERN; |
||
387 | mib[1] = KERN_PROC; |
||
388 | mib[2] = KERN_PROC_PATHNAME; |
||
389 | mib[3] = -1; |
||
390 | path_buf_size = PATH_MAX; |
||
391 | executable_path = (char *)g_malloc(path_buf_size); |
||
392 | if (sysctl(mib, 4, executable_path, &path_buf_size, NULL, 0) == -1) { |
||
393 | if (errno != ENOMEM) |
||
394 | return NULL; |
||
395 | executable_path = (char *)g_realloc(executable_path, path_buf_size); |
||
396 | if (sysctl(mib, 4, executable_path, &path_buf_size, NULL, 0) == -1) |
||
397 | return NULL; |
||
398 | } |
||
399 | return executable_path; |
||
400 | #elif defined(__NetBSD__) |
||
401 | /* |
||
402 | * In all versions of NetBSD's dynamic linker as of 2013-08-12, |
||
403 | * dladdr(main) supplies a path based on argv[0], so we use |
||
404 | * /proc/curproc/exe instead. |
||
405 | * |
||
406 | * XXX - are there OS versions that support "exe" but not "curproc" |
||
407 | * or "self"? Are there any that support "self" but not "curproc"? |
||
408 | */ |
||
409 | static char executable_path[PATH_MAX + 1]; |
||
410 | ssize_t r; |
||
411 | |||
412 | if ((r = readlink("/proc/curproc/exe", executable_path, PATH_MAX)) == -1) |
||
413 | return NULL; |
||
414 | executable_path[r] = '\0'; |
||
415 | return executable_path; |
||
416 | #elif defined(__DragonFly__) |
||
417 | /* |
||
418 | * In older versions of DragonFly BSD's dynamic linker, dladdr(main) |
||
419 | * supplies a path based on argv[0], so we use /proc/curproc/file |
||
420 | * instead; it appears to be supported by all versions of DragonFly |
||
421 | * BSD. |
||
422 | */ |
||
423 | static char executable_path[PATH_MAX + 1]; |
||
424 | ssize_t r; |
||
425 | |||
426 | if ((r = readlink("/proc/curproc/file", executable_path, PATH_MAX)) == -1) |
||
427 | return NULL; |
||
428 | executable_path[r] = '\0'; |
||
429 | return executable_path; |
||
430 | #elif (defined(sun) || defined(__sun)) && defined(HAVE_GETEXECNAME) |
||
431 | /* |
||
432 | * It appears that getexecname() dates back to at least Solaris 8, |
||
433 | * but /proc/{pid}/path is first documented in the Solaris 10 documentation, |
||
434 | * so we use getexecname() if available, rather than /proc/self/path/a.out |
||
435 | * (which isn't documented, but appears to be a symlink to the |
||
436 | * executable image file). |
||
437 | */ |
||
438 | return getexecname(); |
||
439 | #else |
||
440 | /* Fill in your favorite UN*X's code here, if there is something */ |
||
441 | return NULL; |
||
442 | #endif |
||
443 | } |
||
444 | #endif /* _WIN32 */ |
||
445 | |||
446 | /* |
||
447 | * Get the pathname of the directory from which the executable came, |
||
448 | * and save it for future use. Returns NULL on success, and a |
||
449 | * g_mallocated string containing an error on failure. |
||
450 | */ |
||
451 | char * |
||
452 | init_progfile_dir(const char *arg0 |
||
453 | #ifdef _WIN32 |
||
454 | _U_ |
||
455 | #endif |
||
456 | , int (*function_addr)(int, char **) |
||
457 | #if defined(_WIN32) || !defined(HAVE_DLADDR) |
||
458 | _U_ |
||
459 | #endif |
||
460 | ) |
||
461 | { |
||
462 | #ifdef _WIN32 |
||
463 | TCHAR prog_pathname_w[_MAX_PATH+2]; |
||
464 | char *prog_pathname; |
||
465 | DWORD error; |
||
466 | TCHAR *msg_w; |
||
467 | guchar *msg; |
||
468 | size_t msglen; |
||
469 | |||
470 | /* |
||
471 | * Attempt to get the full pathname of the currently running |
||
472 | * program. |
||
473 | */ |
||
474 | if (GetModuleFileName(NULL, prog_pathname_w, G_N_ELEMENTS(prog_pathname_w)) != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { |
||
475 | /* |
||
476 | * XXX - Should we use g_utf16_to_utf8()? |
||
477 | */ |
||
478 | prog_pathname = utf_16to8(prog_pathname_w); |
||
479 | /* |
||
480 | * We got it; strip off the last component, which would be |
||
481 | * the file name of the executable, giving us the pathname |
||
482 | * of the directory where the executable resides. |
||
483 | */ |
||
484 | progfile_dir = g_path_get_dirname(prog_pathname); |
||
485 | if (progfile_dir != NULL) { |
||
486 | return NULL; /* we succeeded */ |
||
487 | } else { |
||
488 | /* |
||
489 | * OK, no. What do we do now? |
||
490 | */ |
||
491 | return g_strdup_printf("No \\ in executable pathname \"%s\"", |
||
492 | prog_pathname); |
||
493 | } |
||
494 | } else { |
||
495 | /* |
||
496 | * Oh, well. Return an indication of the error. |
||
497 | */ |
||
498 | error = GetLastError(); |
||
499 | if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, |
||
500 | NULL, error, 0, (LPTSTR) &msg_w, 0, NULL) == 0) { |
||
501 | /* |
||
502 | * Gak. We can't format the message. |
||
503 | */ |
||
504 | return g_strdup_printf("GetModuleFileName failed: %u (FormatMessage failed: %u)", |
||
505 | error, GetLastError()); |
||
506 | } |
||
507 | msg = utf_16to8(msg_w); |
||
508 | LocalFree(msg_w); |
||
509 | /* |
||
510 | * "FormatMessage()" "helpfully" sticks CR/LF at the |
||
511 | * end of the message. Get rid of it. |
||
512 | */ |
||
513 | msglen = strlen(msg); |
||
514 | if (msglen >= 2) { |
||
515 | msg[msglen - 1] = '\0'; |
||
516 | msg[msglen - 2] = '\0'; |
||
517 | } |
||
518 | return g_strdup_printf("GetModuleFileName failed: %s (%u)", |
||
519 | msg, error); |
||
520 | } |
||
521 | #else |
||
522 | #ifdef HAVE_DLADDR |
||
523 | Dl_info info; |
||
524 | #endif |
||
525 | const char *execname; |
||
526 | char *prog_pathname; |
||
527 | char *curdir; |
||
528 | long path_max; |
||
529 | const char *pathstr; |
||
530 | const char *path_start, *path_end; |
||
531 | size_t path_component_len, path_len; |
||
532 | char *retstr; |
||
533 | char *path; |
||
534 | char *dir_end; |
||
535 | |||
536 | /* |
||
537 | * Check whether WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set in the |
||
538 | * environment; if so, set running_in_build_directory_flag if we |
||
539 | * weren't started with special privileges. (If we were started |
||
540 | * with special privileges, it's not safe to allow the user to point |
||
541 | * us to some other directory; running_in_build_directory_flag, when |
||
542 | * set, causes us to look for plugins and the like in the build |
||
543 | * directory.) |
||
544 | */ |
||
545 | if (g_getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL |
||
546 | && !started_with_special_privs()) |
||
547 | running_in_build_directory_flag = TRUE; |
||
548 | |||
549 | execname = get_executable_path(); |
||
550 | #ifdef HAVE_DLADDR |
||
551 | if (function_addr != NULL && execname == NULL) { |
||
552 | /* |
||
553 | * Try to use dladdr() to find the pathname of the executable. |
||
554 | * dladdr() is not guaranteed to give you anything better than |
||
555 | * argv[0] (i.e., it might not contain a / at all, much less |
||
556 | * being an absolute path), and doesn't appear to do so on |
||
557 | * Linux, but on other platforms it could give you an absolute |
||
558 | * path and obviate the need for us to determine the absolute |
||
559 | * path. |
||
560 | */ |
||
561 | DIAG_OFF(pedantic) |
||
562 | if (dladdr((void *)function_addr, &info)) { |
||
563 | DIAG_ON(pedantic) |
||
564 | execname = info.dli_fname; |
||
565 | } |
||
566 | } |
||
567 | #endif |
||
568 | if (execname == NULL) { |
||
569 | /* |
||
570 | * OK, guess based on argv[0]. |
||
571 | */ |
||
572 | execname = arg0; |
||
573 | } |
||
574 | |||
575 | /* |
||
576 | * Try to figure out the directory in which the currently running |
||
577 | * program resides, given something purporting to be the executable |
||
578 | * name (from dladdr() or from the argv[0] it was started with. |
||
579 | * That might be the absolute path of the program, or a path relative |
||
580 | * to the current directory of the process that started it, or |
||
581 | * just a name for the program if it was started from the command |
||
582 | * line and was searched for in $PATH. It's not guaranteed to be |
||
583 | * any of those, however, so there are no guarantees.... |
||
584 | */ |
||
585 | if (execname[0] == '/') { |
||
586 | /* |
||
587 | * It's an absolute path. |
||
588 | */ |
||
589 | prog_pathname = g_strdup(execname); |
||
590 | } else if (strchr(execname, '/') != NULL) { |
||
591 | /* |
||
592 | * It's a relative path, with a directory in it. |
||
593 | * Get the current directory, and combine it |
||
594 | * with that directory. |
||
595 | */ |
||
596 | path_max = pathconf(".", _PC_PATH_MAX); |
||
597 | if (path_max == -1) { |
||
598 | /* |
||
599 | * We have no idea how big a buffer to |
||
600 | * allocate for the current directory. |
||
601 | */ |
||
602 | return g_strdup_printf("pathconf failed: %s\n", |
||
603 | g_strerror(errno)); |
||
604 | } |
||
605 | curdir = (char *)g_malloc(path_max); |
||
606 | if (getcwd(curdir, path_max) == NULL) { |
||
607 | /* |
||
608 | * It failed - give up, and just stick |
||
609 | * with DATAFILE_DIR. |
||
610 | */ |
||
611 | g_free(curdir); |
||
612 | return g_strdup_printf("getcwd failed: %s\n", |
||
613 | g_strerror(errno)); |
||
614 | } |
||
615 | path = g_strdup_printf("%s/%s", curdir, execname); |
||
616 | g_free(curdir); |
||
617 | prog_pathname = path; |
||
618 | } else { |
||
619 | /* |
||
620 | * It's just a file name. |
||
621 | * Search the path for a file with that name |
||
622 | * that's executable. |
||
623 | */ |
||
624 | prog_pathname = NULL; /* haven't found it yet */ |
||
625 | pathstr = g_getenv("PATH"); |
||
626 | path_start = pathstr; |
||
627 | if (path_start != NULL) { |
||
628 | while (*path_start != '\0') { |
||
629 | path_end = strchr(path_start, ':'); |
||
630 | if (path_end == NULL) |
||
631 | path_end = path_start + strlen(path_start); |
||
632 | path_component_len = path_end - path_start; |
||
633 | path_len = path_component_len + 1 |
||
634 | + strlen(execname) + 1; |
||
635 | path = (char *)g_malloc(path_len); |
||
636 | memcpy(path, path_start, path_component_len); |
||
637 | path[path_component_len] = '\0'; |
||
638 | g_strlcat(path, "/", path_len); |
||
639 | g_strlcat(path, execname, path_len); |
||
640 | if (access(path, X_OK) == 0) { |
||
641 | /* |
||
642 | * Found it! |
||
643 | */ |
||
644 | prog_pathname = path; |
||
645 | break; |
||
646 | } |
||
647 | |||
648 | /* |
||
649 | * That's not it. If there are more |
||
650 | * path components to test, try them. |
||
651 | */ |
||
652 | if (*path_end == '\0') { |
||
653 | /* |
||
654 | * There's nothing more to try. |
||
655 | */ |
||
656 | break; |
||
657 | } |
||
658 | if (*path_end == ':') |
||
659 | path_end++; |
||
660 | path_start = path_end; |
||
661 | g_free(path); |
||
662 | } |
||
663 | if (prog_pathname == NULL) { |
||
664 | /* |
||
665 | * Program not found in path. |
||
666 | */ |
||
667 | return g_strdup_printf("\"%s\" not found in \"%s\"", |
||
668 | execname, pathstr); |
||
669 | } |
||
670 | } else { |
||
671 | /* |
||
672 | * PATH isn't set. |
||
673 | * XXX - should we pick a default? |
||
674 | */ |
||
675 | return g_strdup("PATH isn't set"); |
||
676 | } |
||
677 | } |
||
678 | |||
679 | /* |
||
680 | * OK, we have what we think is the pathname |
||
681 | * of the program. |
||
682 | * |
||
683 | * First, find the last "/" in the directory, |
||
684 | * as that marks the end of the directory pathname. |
||
685 | */ |
||
686 | dir_end = strrchr(prog_pathname, '/'); |
||
687 | if (dir_end != NULL) { |
||
688 | /* |
||
689 | * Found it. Strip off the last component, |
||
690 | * as that's the path of the program. |
||
691 | */ |
||
692 | *dir_end = '\0'; |
||
693 | |||
694 | /* |
||
695 | * Is there a "/.libs" at the end? |
||
696 | */ |
||
697 | dir_end = strrchr(prog_pathname, '/'); |
||
698 | if (dir_end != NULL) { |
||
699 | if (strcmp(dir_end, "/.libs") == 0) { |
||
700 | /* |
||
701 | * Yup, it's ".libs". |
||
702 | * Strip that off; it's an |
||
703 | * artifact of libtool. |
||
704 | */ |
||
705 | *dir_end = '\0'; |
||
706 | |||
707 | /* |
||
708 | * This presumably means we're run from |
||
709 | * the libtool wrapper, which probably |
||
710 | * means we're being run from the build |
||
711 | * directory. If we weren't started |
||
712 | * with special privileges, set |
||
713 | * running_in_build_directory_flag. |
||
714 | * |
||
715 | * XXX - should we check whether what |
||
716 | * follows ".libs/" begins with "lt-"? |
||
717 | */ |
||
718 | if (!started_with_special_privs()) |
||
719 | running_in_build_directory_flag = TRUE; |
||
720 | } |
||
721 | else if (!started_with_special_privs()) { |
||
722 | /* |
||
723 | * Check for the CMake output directory. As people may name |
||
724 | * their directories "run" (really?), also check for the |
||
725 | * CMakeCache.txt file before assuming a CMake output dir. |
||
726 | */ |
||
727 | if (strcmp(dir_end, "/run") == 0) { |
||
728 | gchar *cmake_file; |
||
729 | cmake_file = g_strdup_printf("%.*s/CMakeCache.txt", |
||
730 | (int)(dir_end - prog_pathname), |
||
731 | prog_pathname); |
||
732 | if (file_exists(cmake_file)) |
||
733 | running_in_build_directory_flag = TRUE; |
||
734 | g_free(cmake_file); |
||
735 | } |
||
736 | #ifdef __APPLE__ |
||
737 | if (!running_in_build_directory_flag) { |
||
738 | /* |
||
739 | * Scan up the path looking for a component |
||
740 | * named "Contents". If we find it, we assume |
||
741 | * we're in a bundle, and that the top-level |
||
742 | * directory of the bundle is the one containing |
||
743 | * "Contents". |
||
744 | * |
||
745 | * Not all executables are in the Contents/MacOS |
||
746 | * directory, so we can't just check for those |
||
747 | * in the path and strip them off. |
||
748 | * |
||
749 | * XXX - should we assume that it's either |
||
750 | * Contents/MacOS or Resources/bin? |
||
751 | */ |
||
752 | char *component_end, *p; |
||
753 | |||
754 | component_end = strchr(prog_pathname, '\0'); |
||
755 | p = component_end; |
||
756 | for (;;) { |
||
757 | while (p >= prog_pathname && *p != '/') |
||
758 | p--; |
||
759 | if (p == prog_pathname) { |
||
760 | /* |
||
761 | * We're looking at the first component of |
||
762 | * the pathname now, so we're definitely |
||
763 | * not in a bundle, even if we're in |
||
764 | * "/Contents". |
||
765 | */ |
||
766 | break; |
||
767 | } |
||
768 | if (strncmp(p, "/Contents", component_end - p) == 0) { |
||
769 | /* Found it. */ |
||
770 | appbundle_dir = (char *)g_malloc(p - prog_pathname + 1); |
||
771 | memcpy(appbundle_dir, prog_pathname, p - prog_pathname); |
||
772 | appbundle_dir[p - prog_pathname] = '\0'; |
||
773 | break; |
||
774 | } |
||
775 | component_end = p; |
||
776 | p--; |
||
777 | } |
||
778 | } |
||
779 | #endif |
||
780 | } |
||
781 | } |
||
782 | |||
783 | /* |
||
784 | * OK, we have the path we want. |
||
785 | */ |
||
786 | progfile_dir = prog_pathname; |
||
787 | return NULL; |
||
788 | } else { |
||
789 | /* |
||
790 | * This "shouldn't happen"; we apparently |
||
791 | * have no "/" in the pathname. |
||
792 | * Just free up prog_pathname. |
||
793 | */ |
||
794 | retstr = g_strdup_printf("No / found in \"%s\"", prog_pathname); |
||
795 | g_free(prog_pathname); |
||
796 | return retstr; |
||
797 | } |
||
798 | #endif |
||
799 | } |
||
800 | |||
801 | /* |
||
802 | * Get the directory in which the program resides. |
||
803 | */ |
||
804 | const char * |
||
805 | get_progfile_dir(void) |
||
806 | { |
||
807 | return progfile_dir; |
||
808 | } |
||
809 | |||
810 | /* |
||
811 | * Get the directory in which the global configuration and data files are |
||
812 | * stored. |
||
813 | * |
||
814 | * On Windows, we use the directory in which the executable for this |
||
815 | * process resides. |
||
816 | * |
||
817 | * On UN*X, we use the DATAFILE_DIR value supplied by the configure |
||
818 | * script, unless we think we're being run from the build directory, |
||
819 | * in which case we use the directory in which the executable for this |
||
820 | * process resides. |
||
821 | * |
||
822 | * XXX - if we ever make libwireshark a real library, used by multiple |
||
823 | * applications (more than just TShark and versions of Wireshark with |
||
824 | * various UIs), should the configuration files belong to the library |
||
825 | * (and be shared by all those applications) or to the applications? |
||
826 | * |
||
827 | * If they belong to the library, that could be done on UNIX by the |
||
828 | * configure script, but it's trickier on Windows, as you can't just |
||
829 | * use the pathname of the executable. |
||
830 | * |
||
831 | * If they belong to the application, that could be done on Windows |
||
832 | * by using the pathname of the executable, but we'd have to have it |
||
833 | * passed in as an argument, in some call, on UNIX. |
||
834 | * |
||
835 | * Note that some of those configuration files might be used by code in |
||
836 | * libwireshark, some of them might be used by dissectors (would they |
||
837 | * belong to libwireshark, the application, or a separate library?), |
||
838 | * and some of them might be used by other code (the Wireshark preferences |
||
839 | * file includes resolver preferences that control the behavior of code |
||
840 | * in libwireshark, dissector preferences, and UI preferences, for |
||
841 | * example). |
||
842 | */ |
||
843 | const char * |
||
844 | get_datafile_dir(void) |
||
845 | { |
||
846 | static const char *datafile_dir = NULL; |
||
847 | |||
848 | if (datafile_dir != NULL) |
||
849 | return datafile_dir; |
||
850 | |||
851 | #ifdef _WIN32 |
||
852 | /* |
||
853 | * Do we have the pathname of the program? If so, assume we're |
||
854 | * running an installed version of the program. If we fail, |
||
855 | * we don't change "datafile_dir", and thus end up using the |
||
856 | * default. |
||
857 | * |
||
858 | * XXX - does NSIS put the installation directory into |
||
859 | * "\HKEY_LOCAL_MACHINE\SOFTWARE\Wireshark\InstallDir"? |
||
860 | * If so, perhaps we should read that from the registry, |
||
861 | * instead. |
||
862 | */ |
||
863 | if (progfile_dir != NULL) { |
||
864 | /* |
||
865 | * Yes, we do; use that. |
||
866 | */ |
||
867 | datafile_dir = progfile_dir; |
||
868 | } else { |
||
869 | /* |
||
870 | * No, we don't. |
||
871 | * Fall back on the default installation directory. |
||
872 | */ |
||
873 | datafile_dir = "C:\\Program Files\\Wireshark\\"; |
||
874 | } |
||
875 | #else |
||
876 | |||
877 | if (running_in_build_directory_flag) { |
||
878 | /* |
||
879 | * We're (probably) being run from the build directory and |
||
880 | * weren't started with special privileges. |
||
881 | * |
||
882 | * (running_in_build_directory_flag is never set to TRUE |
||
883 | * if we're started with special privileges, so we need |
||
884 | * only check it; we don't need to call started_with_special_privs().) |
||
885 | * |
||
886 | * Use the top-level source directory as the datafile directory |
||
887 | * because most of our data files (radius/, COPYING) are there. |
||
888 | */ |
||
889 | datafile_dir = g_strdup(TOP_SRCDIR); |
||
890 | return datafile_dir; |
||
891 | } else { |
||
892 | if (g_getenv("WIRESHARK_DATA_DIR") && !started_with_special_privs()) { |
||
893 | /* |
||
894 | * The user specified a different directory for data files |
||
895 | * and we aren't running with special privileges. |
||
896 | * XXX - We might be able to dispense with the priv check |
||
897 | */ |
||
898 | datafile_dir = g_strdup(g_getenv("WIRESHARK_DATA_DIR")); |
||
899 | } |
||
900 | #ifdef __APPLE__ |
||
901 | /* |
||
902 | * If we're running from an app bundle and weren't started |
||
903 | * with special privileges, use the Contents/Resources/share/wireshark |
||
904 | * subdirectory of the app bundle. |
||
905 | * |
||
906 | * (appbundle_dir is not set to a non-null value if we're |
||
907 | * started with special privileges, so we need only check |
||
908 | * it; we don't need to call started_with_special_privs().) |
||
909 | */ |
||
910 | else if (appbundle_dir != NULL) { |
||
911 | datafile_dir = g_strdup_printf("%s/Contents/Resources/share/wireshark", |
||
912 | appbundle_dir); |
||
913 | } |
||
914 | #endif |
||
915 | else { |
||
916 | datafile_dir = DATAFILE_DIR; |
||
917 | } |
||
918 | } |
||
919 | |||
920 | #endif |
||
921 | return datafile_dir; |
||
922 | } |
||
923 | |||
924 | #if defined(HAVE_PLUGINS) || defined(HAVE_LUA) |
||
925 | /* |
||
926 | * Find the directory where the plugins are stored. |
||
927 | * |
||
928 | * On Windows, we use the "plugin" subdirectory of the datafile directory. |
||
929 | * |
||
930 | * On UN*X, we use the PLUGIN_INSTALL_DIR value supplied by the configure |
||
931 | * script, unless we think we're being run from the build directory, |
||
932 | * in which case we use the "plugin" subdirectory of the datafile directory. |
||
933 | * |
||
934 | * In both cases, we then use the subdirectory of that directory whose |
||
935 | * name is the version number. |
||
936 | * |
||
937 | * XXX - if we think we're being run from the build directory, perhaps we |
||
938 | * should have the plugin code not look in the version subdirectory |
||
939 | * of the plugin directory, but look in all of the subdirectories |
||
940 | * of the plugin directory, so it can just fetch the plugins built |
||
941 | * as part of the build process. |
||
942 | */ |
||
943 | static const char *plugin_dir = NULL; |
||
944 | |||
945 | static void |
||
946 | init_plugin_dir(void) |
||
947 | { |
||
948 | #ifdef _WIN32 |
||
949 | /* |
||
950 | * On Windows, the data file directory is the installation |
||
951 | * directory; the plugins are stored under it. |
||
952 | * |
||
953 | * Assume we're running the installed version of Wireshark; |
||
954 | * on Windows, the data file directory is the directory |
||
955 | * in which the Wireshark binary resides. |
||
956 | */ |
||
957 | plugin_dir = g_strdup_printf("%s\\plugins\\%s", get_datafile_dir(), |
||
958 | VERSION); |
||
959 | |||
960 | /* |
||
961 | * Make sure that pathname refers to a directory. |
||
962 | */ |
||
963 | if (test_for_directory(plugin_dir) != EISDIR) { |
||
964 | /* |
||
965 | * Either it doesn't refer to a directory or it |
||
966 | * refers to something that doesn't exist. |
||
967 | * |
||
968 | * Assume that means we're running a version of |
||
969 | * Wireshark we've built in a build directory, |
||
970 | * in which case {datafile dir}\plugins is the |
||
971 | * top-level plugins source directory, and use |
||
972 | * that directory and set the "we're running in |
||
973 | * a build directory" flag, so the plugin |
||
974 | * scanner will check all subdirectories of that |
||
975 | * directory for plugins. |
||
976 | */ |
||
977 | g_free( (gpointer) plugin_dir); |
||
978 | plugin_dir = g_strdup_printf("%s\\plugins", get_datafile_dir()); |
||
979 | running_in_build_directory_flag = TRUE; |
||
980 | } |
||
981 | #else |
||
982 | if (running_in_build_directory_flag) { |
||
983 | /* |
||
984 | * We're (probably) being run from the build directory and |
||
985 | * weren't started with special privileges, so we'll use |
||
986 | * the "plugins" subdirectory of the directory where the program |
||
987 | * we're running is (that's the build directory). |
||
988 | */ |
||
989 | plugin_dir = g_strdup_printf("%s/plugins", get_progfile_dir()); |
||
990 | } else { |
||
991 | if (g_getenv("WIRESHARK_PLUGIN_DIR") && !started_with_special_privs()) { |
||
992 | /* |
||
993 | * The user specified a different directory for plugins |
||
994 | * and we aren't running with special privileges. |
||
995 | */ |
||
996 | plugin_dir = g_strdup(g_getenv("WIRESHARK_PLUGIN_DIR")); |
||
997 | } |
||
998 | #ifdef __APPLE__ |
||
999 | /* |
||
1000 | * If we're running from an app bundle and weren't started |
||
1001 | * with special privileges, use the Contents/PlugIns/wireshark |
||
1002 | * subdirectory of the app bundle. |
||
1003 | * |
||
1004 | * (appbundle_dir is not set to a non-null value if we're |
||
1005 | * started with special privileges, so we need only check |
||
1006 | * it; we don't need to call started_with_special_privs().) |
||
1007 | */ |
||
1008 | else if (appbundle_dir != NULL) { |
||
1009 | plugin_dir = g_strdup_printf("%s/Contents/PlugIns/wireshark", |
||
1010 | appbundle_dir); |
||
1011 | } |
||
1012 | #endif |
||
1013 | else { |
||
1014 | plugin_dir = PLUGIN_INSTALL_DIR; |
||
1015 | } |
||
1016 | } |
||
1017 | #endif |
||
1018 | } |
||
1019 | #endif /* HAVE_PLUGINS || HAVE_LUA */ |
||
1020 | |||
1021 | /* |
||
1022 | * Get the directory in which the plugins are stored. |
||
1023 | */ |
||
1024 | const char * |
||
1025 | get_plugin_dir(void) |
||
1026 | { |
||
1027 | #if defined(HAVE_PLUGINS) || defined(HAVE_LUA) |
||
1028 | if (!plugin_dir) init_plugin_dir(); |
||
1029 | return plugin_dir; |
||
1030 | #else |
||
1031 | return NULL; |
||
1032 | #endif |
||
1033 | } |
||
1034 | |||
1035 | #if defined(HAVE_EXTCAP) |
||
1036 | /* |
||
1037 | * Find the directory where the extcap hooks are stored. |
||
1038 | * |
||
1039 | * On Windows, we use the "extcap" subdirectory of the datafile directory. |
||
1040 | * |
||
1041 | * On UN*X, we use the EXTCAP_DIR value supplied by the configure |
||
1042 | * script, unless we think we're being run from the build directory, |
||
1043 | * in which case we use the "extcap" subdirectory of the datafile directory. |
||
1044 | * |
||
1045 | * In both cases, we then use the subdirectory of that directory whose |
||
1046 | * name is the version number. |
||
1047 | * |
||
1048 | * XXX - if we think we're being run from the build directory, perhaps we |
||
1049 | * should have the extcap code not look in the version subdirectory |
||
1050 | * of the extcap directory, but look in all of the subdirectories |
||
1051 | * of the extcap directory, so it can just fetch the extcap hooks built |
||
1052 | * as part of the build process. |
||
1053 | */ |
||
1054 | static const char *extcap_dir = NULL; |
||
1055 | |||
1056 | static void init_extcap_dir(void) { |
||
1057 | #ifdef _WIN32 |
||
1058 | const char *alt_extcap_path; |
||
1059 | |||
1060 | /* |
||
1061 | * On Windows, the data file directory is the installation |
||
1062 | * directory; the extcap hooks are stored under it. |
||
1063 | * |
||
1064 | * Assume we're running the installed version of Wireshark; |
||
1065 | * on Windows, the data file directory is the directory |
||
1066 | * in which the Wireshark binary resides. |
||
1067 | */ |
||
1068 | alt_extcap_path = g_getenv("WIRESHARK_EXTCAP_DIR"); |
||
1069 | if (alt_extcap_path) { |
||
1070 | /* |
||
1071 | * The user specified a different directory for extcap hooks. |
||
1072 | */ |
||
1073 | extcap_dir = g_strdup(alt_extcap_path); |
||
1074 | } else { |
||
1075 | extcap_dir = g_strdup_printf("%s\\extcap", get_datafile_dir()); |
||
1076 | } |
||
1077 | #else |
||
1078 | if (running_in_build_directory_flag) { |
||
1079 | /* |
||
1080 | * We're (probably) being run from the build directory and |
||
1081 | * weren't started with special privileges, so we'll use |
||
1082 | * the "extcap hooks" subdirectory of the directory where the program |
||
1083 | * we're running is (that's the build directory). |
||
1084 | */ |
||
1085 | extcap_dir = g_strdup_printf("%s/extcap", get_progfile_dir()); |
||
1086 | } else { |
||
1087 | if (g_getenv("WIRESHARK_EXTCAP_DIR") && !started_with_special_privs()) { |
||
1088 | /* |
||
1089 | * The user specified a different directory for extcap hooks |
||
1090 | * and we aren't running with special privileges. |
||
1091 | */ |
||
1092 | extcap_dir = g_strdup(g_getenv("WIRESHARK_EXTCAP_DIR")); |
||
1093 | } |
||
1094 | #ifdef __APPLE__ |
||
1095 | /* |
||
1096 | * If we're running from an app bundle and weren't started |
||
1097 | * with special privileges, use the Contents/MacOS/extcap |
||
1098 | * subdirectory of the app bundle. |
||
1099 | * |
||
1100 | * (appbundle_dir is not set to a non-null value if we're |
||
1101 | * started with special privileges, so we need only check |
||
1102 | * it; we don't need to call started_with_special_privs().) |
||
1103 | */ |
||
1104 | else if (appbundle_dir != NULL) { |
||
1105 | extcap_dir = g_strdup_printf("%s/Contents/MacOS/extcap", |
||
1106 | appbundle_dir); |
||
1107 | } |
||
1108 | #endif |
||
1109 | else { |
||
1110 | extcap_dir = EXTCAP_DIR; |
||
1111 | } |
||
1112 | } |
||
1113 | #endif |
||
1114 | } |
||
1115 | #endif /* HAVE_EXTCAP */ |
||
1116 | |||
1117 | /* |
||
1118 | * Get the directory in which the extcap hooks are stored. |
||
1119 | * |
||
1120 | * XXX - A fix instead of HAVE_EXTCAP must be found |
||
1121 | */ |
||
1122 | const char * |
||
1123 | get_extcap_dir(void) { |
||
1124 | #if defined(HAVE_EXTCAP) |
||
1125 | if (!extcap_dir) |
||
1126 | init_extcap_dir(); |
||
1127 | return extcap_dir; |
||
1128 | #else |
||
1129 | return NULL; |
||
1130 | #endif |
||
1131 | } |
||
1132 | |||
1133 | /* |
||
1134 | * Get the flag indicating whether we're running from a build |
||
1135 | * directory. |
||
1136 | */ |
||
1137 | gboolean |
||
1138 | running_in_build_directory(void) |
||
1139 | { |
||
1140 | return running_in_build_directory_flag; |
||
1141 | } |
||
1142 | |||
1143 | /* |
||
1144 | * Get the directory in which files that, at least on UNIX, are |
||
1145 | * system files (such as "/etc/ethers") are stored; on Windows, |
||
1146 | * there's no "/etc" directory, so we get them from the global |
||
1147 | * configuration and data file directory. |
||
1148 | */ |
||
1149 | const char * |
||
1150 | get_systemfile_dir(void) |
||
1151 | { |
||
1152 | #ifdef _WIN32 |
||
1153 | return get_datafile_dir(); |
||
1154 | #else |
||
1155 | return "/etc"; |
||
1156 | #endif |
||
1157 | } |
||
1158 | |||
1159 | void |
||
1160 | set_profile_name(const gchar *profilename) |
||
1161 | { |
||
1162 | g_free (persconfprofile); |
||
1163 | |||
1164 | if (profilename && strlen(profilename) > 0 && |
||
1165 | strcmp(profilename, DEFAULT_PROFILE) != 0) { |
||
1166 | persconfprofile = g_strdup (profilename); |
||
1167 | } else { |
||
1168 | /* Default Profile */ |
||
1169 | persconfprofile = NULL; |
||
1170 | } |
||
1171 | } |
||
1172 | |||
1173 | const char * |
||
1174 | get_profile_name(void) |
||
1175 | { |
||
1176 | if (persconfprofile) { |
||
1177 | return persconfprofile; |
||
1178 | } else { |
||
1179 | return DEFAULT_PROFILE; |
||
1180 | } |
||
1181 | } |
||
1182 | |||
1183 | gboolean |
||
1184 | is_default_profile(void) |
||
1185 | { |
||
1186 | return (!persconfprofile || strcmp(persconfprofile, DEFAULT_PROFILE) == 0) ? TRUE : FALSE; |
||
1187 | } |
||
1188 | |||
1189 | gboolean |
||
1190 | has_global_profiles(void) |
||
1191 | { |
||
1192 | WS_DIR *dir; |
||
1193 | WS_DIRENT *file; |
||
1194 | const gchar *global_dir = get_global_profiles_dir(); |
||
1195 | gchar *filename; |
||
1196 | gboolean has_global = FALSE; |
||
1197 | |||
1198 | if ((test_for_directory(global_dir) == EISDIR) && |
||
1199 | ((dir = ws_dir_open(global_dir, 0, NULL)) != NULL)) |
||
1200 | { |
||
1201 | while ((file = ws_dir_read_name(dir)) != NULL) { |
||
1202 | filename = g_strdup_printf ("%s%s%s", global_dir, G_DIR_SEPARATOR_S, |
||
1203 | ws_dir_get_name(file)); |
||
1204 | if (test_for_directory(filename) == EISDIR) { |
||
1205 | has_global = TRUE; |
||
1206 | g_free (filename); |
||
1207 | break; |
||
1208 | } |
||
1209 | g_free (filename); |
||
1210 | } |
||
1211 | ws_dir_close(dir); |
||
1212 | } |
||
1213 | |||
1214 | return has_global; |
||
1215 | } |
||
1216 | |||
1217 | void |
||
1218 | profile_store_persconffiles(gboolean store) |
||
1219 | { |
||
1220 | if (store) { |
||
1221 | profile_files = g_hash_table_new (g_str_hash, g_str_equal); |
||
1222 | } |
||
1223 | do_store_persconffiles = store; |
||
1224 | } |
||
1225 | |||
1226 | /* |
||
1227 | * Get the directory in which personal configuration files reside. |
||
1228 | * |
||
1229 | * On Windows, it's "Wireshark", under %APPDATA% or, if %APPDATA% isn't set, |
||
1230 | * it's "%USERPROFILE%\Application Data" (which is what %APPDATA% normally |
||
1231 | * is on Windows 2000). |
||
1232 | * |
||
1233 | * On UNIX-compatible systems, we first look in XDG_CONFIG_HOME/wireshark |
||
1234 | * and, if that doesn't exist, ~/.wireshark, for backwards compatibility. |
||
1235 | * If neither exists, we use XDG_CONFIG_HOME/wireshark, so that the directory |
||
1236 | * is initially created as XDG_CONFIG_HOME/wireshark. We use that regardless |
||
1237 | * of whether the user is running under an XDG desktop or not, so that |
||
1238 | * if the user's home directory is on a server and shared between |
||
1239 | * different desktop environments on different machines, they can all |
||
1240 | * share the same configuration file directory. |
||
1241 | * |
||
1242 | * XXX - what about stuff that shouldn't be shared between machines, |
||
1243 | * such as plugins in the form of shared loadable images? |
||
1244 | */ |
||
1245 | static const char * |
||
1246 | get_persconffile_dir_no_profile(void) |
||
1247 | { |
||
1248 | #ifdef _WIN32 |
||
1249 | const char *env; |
||
1250 | #else |
||
1251 | char *xdg_path, *path; |
||
1252 | struct passwd *pwd; |
||
1253 | const char *homedir; |
||
1254 | #endif |
||
1255 | |||
1256 | /* Return the cached value, if available */ |
||
1257 | if (persconffile_dir != NULL) |
||
1258 | return persconffile_dir; |
||
1259 | |||
1260 | #ifdef _WIN32 |
||
1261 | /* |
||
1262 | * See if the user has selected an alternate environment. |
||
1263 | */ |
||
1264 | env = g_getenv("WIRESHARK_APPDATA"); |
||
1265 | if (env != NULL) { |
||
1266 | persconffile_dir = g_strdup(env); |
||
1267 | return persconffile_dir; |
||
1268 | } |
||
1269 | |||
1270 | /* |
||
1271 | * Use %APPDATA% or %USERPROFILE%, so that configuration |
||
1272 | * files are stored in the user profile, rather than in |
||
1273 | * the home directory. The Windows convention is to store |
||
1274 | * configuration information in the user profile, and doing |
||
1275 | * so means you can use Wireshark even if the home directory |
||
1276 | * is an inaccessible network drive. |
||
1277 | */ |
||
1278 | env = g_getenv("APPDATA"); |
||
1279 | if (env != NULL) { |
||
1280 | /* |
||
1281 | * Concatenate %APPDATA% with "\Wireshark". |
||
1282 | */ |
||
1283 | persconffile_dir = g_build_filename(env, "Wireshark", NULL); |
||
1284 | return persconffile_dir; |
||
1285 | } |
||
1286 | |||
1287 | /* |
||
1288 | * OK, %APPDATA% wasn't set, so use %USERPROFILE%\Application Data. |
||
1289 | */ |
||
1290 | env = g_getenv("USERPROFILE"); |
||
1291 | if (env != NULL) { |
||
1292 | persconffile_dir = g_build_filename(env, "Application Data", "Wireshark", NULL); |
||
1293 | return persconffile_dir; |
||
1294 | } |
||
1295 | |||
1296 | /* |
||
1297 | * Give up and use "C:". |
||
1298 | */ |
||
1299 | persconffile_dir = g_build_filename("C:", "Wireshark", NULL); |
||
1300 | return persconffile_dir; |
||
1301 | #else |
||
1302 | /* |
||
1303 | * Check if XDG_CONFIG_HOME/wireshark exists and is a directory. |
||
1304 | */ |
||
1305 | xdg_path = g_build_filename(g_get_user_config_dir(), "wireshark", NULL); |
||
1306 | if (g_file_test(xdg_path, G_FILE_TEST_IS_DIR)) { |
||
1307 | persconffile_dir = xdg_path; |
||
1308 | return persconffile_dir; |
||
1309 | } |
||
1310 | |||
1311 | /* |
||
1312 | * It doesn't exist, or it does but isn't a directory, so try |
||
1313 | * ~/.wireshark. |
||
1314 | * |
||
1315 | * If $HOME is set, use that for ~. |
||
1316 | * |
||
1317 | * (Note: before GLib 2.36, g_get_home_dir() didn't look at $HOME, |
||
1318 | * but we always want to do so, so we don't use g_get_home_dir().) |
||
1319 | */ |
||
1320 | homedir = g_getenv("HOME"); |
||
1321 | if (homedir == NULL) { |
||
1322 | /* |
||
1323 | * It's not set. |
||
1324 | * |
||
1325 | * Get their home directory from the password file. |
||
1326 | * If we can't even find a password file entry for them, |
||
1327 | * use "/tmp". |
||
1328 | */ |
||
1329 | pwd = getpwuid(getuid()); |
||
1330 | if (pwd != NULL) { |
||
1331 | homedir = pwd->pw_dir; |
||
1332 | } else { |
||
1333 | homedir = "/tmp"; |
||
1334 | } |
||
1335 | } |
||
1336 | path = g_build_filename(homedir, ".wireshark", NULL); |
||
1337 | if (g_file_test(path, G_FILE_TEST_IS_DIR)) { |
||
1338 | g_free(xdg_path); |
||
1339 | persconffile_dir = path; |
||
1340 | return persconffile_dir; |
||
1341 | } |
||
1342 | |||
1343 | /* |
||
1344 | * Neither are directories that exist; use the XDG path, so we'll |
||
1345 | * create that as necessary. |
||
1346 | */ |
||
1347 | g_free(path); |
||
1348 | persconffile_dir = xdg_path; |
||
1349 | return persconffile_dir; |
||
1350 | #endif |
||
1351 | } |
||
1352 | |||
1353 | void |
||
1354 | set_persconffile_dir(const char *p) |
||
1355 | { |
||
1356 | g_free(persconffile_dir); |
||
1357 | persconffile_dir = g_strdup(p); |
||
1358 | } |
||
1359 | |||
1360 | const char * |
||
1361 | get_profiles_dir(void) |
||
1362 | { |
||
1363 | static char *profiles_dir = NULL; |
||
1364 | |||
1365 | g_free (profiles_dir); |
||
1366 | profiles_dir = g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (), |
||
1367 | G_DIR_SEPARATOR_S, PROFILES_DIR); |
||
1368 | |||
1369 | return profiles_dir; |
||
1370 | } |
||
1371 | |||
1372 | const char * |
||
1373 | get_global_profiles_dir(void) |
||
1374 | { |
||
1375 | static char *global_profiles_dir = NULL; |
||
1376 | |||
1377 | if (!global_profiles_dir) { |
||
1378 | global_profiles_dir = g_strdup_printf ("%s%s%s", get_datafile_dir(), |
||
1379 | G_DIR_SEPARATOR_S, PROFILES_DIR); |
||
1380 | } |
||
1381 | |||
1382 | return global_profiles_dir; |
||
1383 | } |
||
1384 | |||
1385 | static const char * |
||
1386 | get_persconffile_dir(const gchar *profilename) |
||
1387 | { |
||
1388 | static char *persconffile_profile_dir = NULL; |
||
1389 | |||
1390 | g_free (persconffile_profile_dir); |
||
1391 | |||
1392 | if (profilename && strlen(profilename) > 0 && |
||
1393 | strcmp(profilename, DEFAULT_PROFILE) != 0) { |
||
1394 | persconffile_profile_dir = g_strdup_printf ("%s%s%s", get_profiles_dir (), |
||
1395 | G_DIR_SEPARATOR_S, profilename); |
||
1396 | } else { |
||
1397 | persconffile_profile_dir = g_strdup (get_persconffile_dir_no_profile ()); |
||
1398 | } |
||
1399 | |||
1400 | return persconffile_profile_dir; |
||
1401 | } |
||
1402 | |||
1403 | gboolean |
||
1404 | profile_exists(const gchar *profilename, gboolean global) |
||
1405 | { |
||
1406 | if (global) { |
||
1407 | gchar *path = g_strdup_printf ("%s%s%s", get_global_profiles_dir(), |
||
1408 | G_DIR_SEPARATOR_S, profilename); |
||
1409 | if (test_for_directory (path) == EISDIR) { |
||
1410 | g_free (path); |
||
1411 | return TRUE; |
||
1412 | } |
||
1413 | g_free (path); |
||
1414 | } else { |
||
1415 | if (test_for_directory (get_persconffile_dir (profilename)) == EISDIR) { |
||
1416 | return TRUE; |
||
1417 | } |
||
1418 | } |
||
1419 | |||
1420 | return FALSE; |
||
1421 | } |
||
1422 | |||
1423 | static int |
||
1424 | delete_directory (const char *directory, char **pf_dir_path_return) |
||
1425 | { |
||
1426 | WS_DIR *dir; |
||
1427 | WS_DIRENT *file; |
||
1428 | gchar *filename; |
||
1429 | int ret = 0; |
||
1430 | |||
1431 | if ((dir = ws_dir_open(directory, 0, NULL)) != NULL) { |
||
1432 | while ((file = ws_dir_read_name(dir)) != NULL) { |
||
1433 | filename = g_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S, |
||
1434 | ws_dir_get_name(file)); |
||
1435 | if (test_for_directory(filename) != EISDIR) { |
||
1436 | ret = ws_remove(filename); |
||
1437 | #if 0 |
||
1438 | } else { |
||
1439 | /* The user has manually created a directory in the profile directory */ |
||
1440 | /* I do not want to delete the directory recursively yet */ |
||
1441 | ret = delete_directory (filename, pf_dir_path_return); |
||
1442 | #endif |
||
1443 | } |
||
1444 | if (ret != 0) { |
||
1445 | *pf_dir_path_return = filename; |
||
1446 | break; |
||
1447 | } |
||
1448 | g_free (filename); |
||
1449 | } |
||
1450 | ws_dir_close(dir); |
||
1451 | } |
||
1452 | |||
1453 | if (ret == 0 && (ret = ws_remove(directory)) != 0) { |
||
1454 | *pf_dir_path_return = g_strdup (directory); |
||
1455 | } |
||
1456 | |||
1457 | return ret; |
||
1458 | } |
||
1459 | |||
1460 | int |
||
1461 | delete_persconffile_profile(const char *profilename, char **pf_dir_path_return) |
||
1462 | { |
||
1463 | const char *profile_dir = get_persconffile_dir(profilename); |
||
1464 | int ret = 0; |
||
1465 | |||
1466 | if (test_for_directory (profile_dir) == EISDIR) { |
||
1467 | ret = delete_directory (profile_dir, pf_dir_path_return); |
||
1468 | } |
||
1469 | |||
1470 | return ret; |
||
1471 | } |
||
1472 | |||
1473 | int |
||
1474 | rename_persconffile_profile(const char *fromname, const char *toname, |
||
1475 | char **pf_from_dir_path_return, char **pf_to_dir_path_return) |
||
1476 | { |
||
1477 | char *from_dir = g_strdup (get_persconffile_dir(fromname)); |
||
1478 | char *to_dir = g_strdup (get_persconffile_dir(toname)); |
||
1479 | int ret = 0; |
||
1480 | |||
1481 | ret = ws_rename (from_dir, to_dir); |
||
1482 | if (ret != 0) { |
||
1483 | *pf_from_dir_path_return = g_strdup (from_dir); |
||
1484 | *pf_to_dir_path_return = g_strdup (to_dir); |
||
1485 | } |
||
1486 | |||
1487 | g_free (from_dir); |
||
1488 | g_free (to_dir); |
||
1489 | |||
1490 | return ret; |
||
1491 | } |
||
1492 | |||
1493 | /* |
||
1494 | * Create the directory that holds personal configuration files, if |
||
1495 | * necessary. If we attempted to create it, and failed, return -1 and |
||
1496 | * set "*pf_dir_path_return" to the pathname of the directory we failed |
||
1497 | * to create (it's g_mallocated, so our caller should free it); otherwise, |
||
1498 | * return 0. |
||
1499 | */ |
||
1500 | int |
||
1501 | create_persconffile_profile(const char *profilename, char **pf_dir_path_return) |
||
1502 | { |
||
1503 | const char *pf_dir_path; |
||
1504 | #ifdef _WIN32 |
||
1505 | char *pf_dir_path_copy, *pf_dir_parent_path; |
||
1506 | size_t pf_dir_parent_path_len; |
||
1507 | #endif |
||
1508 | ws_statb64 s_buf; |
||
1509 | int ret; |
||
1510 | int save_errno; |
||
1511 | |||
1512 | if (profilename) { |
||
1513 | /* |
||
1514 | * Create the "Default" personal configuration files directory, if necessary. |
||
1515 | */ |
||
1516 | if (create_persconffile_profile (NULL, pf_dir_path_return) == -1) { |
||
1517 | return -1; |
||
1518 | } |
||
1519 | |||
1520 | /* |
||
1521 | * Check if profiles directory exists. |
||
1522 | * If not then create it. |
||
1523 | */ |
||
1524 | pf_dir_path = get_profiles_dir (); |
||
1525 | if (ws_stat64(pf_dir_path, &s_buf) != 0) { |
||
1526 | if (errno != ENOENT) { |
||
1527 | /* Some other problem; give up now. */ |
||
1528 | save_errno = errno; |
||
1529 | *pf_dir_path_return = g_strdup(pf_dir_path); |
||
1530 | errno = save_errno; |
||
1531 | return -1; |
||
1532 | } |
||
1533 | |||
1534 | /* |
||
1535 | * It doesn't exist; try to create it. |
||
1536 | */ |
||
1537 | ret = ws_mkdir(pf_dir_path, 0755); |
||
1538 | if (ret == -1) { |
||
1539 | *pf_dir_path_return = g_strdup(pf_dir_path); |
||
1540 | return ret; |
||
1541 | } |
||
1542 | } |
||
1543 | } |
||
1544 | |||
1545 | pf_dir_path = get_persconffile_dir(profilename); |
||
1546 | if (ws_stat64(pf_dir_path, &s_buf) != 0) { |
||
1547 | if (errno != ENOENT) { |
||
1548 | /* Some other problem; give up now. */ |
||
1549 | save_errno = errno; |
||
1550 | *pf_dir_path_return = g_strdup(pf_dir_path); |
||
1551 | errno = save_errno; |
||
1552 | return -1; |
||
1553 | } |
||
1554 | #ifdef _WIN32 |
||
1555 | /* |
||
1556 | * Does the parent directory of that directory |
||
1557 | * exist? %APPDATA% may not exist even though |
||
1558 | * %USERPROFILE% does. |
||
1559 | * |
||
1560 | * We check for the existence of the directory |
||
1561 | * by first checking whether the parent directory |
||
1562 | * is just a drive letter and, if it's not, by |
||
1563 | * doing a "stat()" on it. If it's a drive letter, |
||
1564 | * or if the "stat()" succeeds, we assume it exists. |
||
1565 | */ |
||
1566 | pf_dir_path_copy = g_strdup(pf_dir_path); |
||
1567 | pf_dir_parent_path = get_dirname(pf_dir_path_copy); |
||
1568 | pf_dir_parent_path_len = strlen(pf_dir_parent_path); |
||
1569 | if (pf_dir_parent_path_len > 0 |
||
1570 | && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':' |
||
1571 | && ws_stat64(pf_dir_parent_path, &s_buf) != 0) { |
||
1572 | /* |
||
1573 | * Not a drive letter and the stat() failed. |
||
1574 | */ |
||
1575 | if (errno != ENOENT) { |
||
1576 | /* Some other problem; give up now. */ |
||
1577 | save_errno = errno; |
||
1578 | *pf_dir_path_return = g_strdup(pf_dir_path); |
||
1579 | errno = save_errno; |
||
1580 | return -1; |
||
1581 | } |
||
1582 | /* |
||
1583 | * No, it doesn't exist - make it first. |
||
1584 | */ |
||
1585 | ret = ws_mkdir(pf_dir_parent_path, 0755); |
||
1586 | if (ret == -1) { |
||
1587 | *pf_dir_path_return = pf_dir_parent_path; |
||
1588 | return -1; |
||
1589 | } |
||
1590 | } |
||
1591 | g_free(pf_dir_path_copy); |
||
1592 | ret = ws_mkdir(pf_dir_path, 0755); |
||
1593 | #else |
||
1594 | ret = g_mkdir_with_parents(pf_dir_path, 0755); |
||
1595 | #endif |
||
1596 | } else { |
||
1597 | /* |
||
1598 | * Something with that pathname exists; if it's not |
||
1599 | * a directory, we'll get an error if we try to put |
||
1600 | * something in it, so we don't fail here, we wait |
||
1601 | * for that attempt fo fail. |
||
1602 | */ |
||
1603 | ret = 0; |
||
1604 | } |
||
1605 | if (ret == -1) |
||
1606 | *pf_dir_path_return = g_strdup(pf_dir_path); |
||
1607 | return ret; |
||
1608 | } |
||
1609 | |||
1610 | int |
||
1611 | create_persconffile_dir(char **pf_dir_path_return) |
||
1612 | { |
||
1613 | return create_persconffile_profile(persconfprofile, pf_dir_path_return); |
||
1614 | } |
||
1615 | |||
1616 | int |
||
1617 | copy_persconffile_profile(const char *toname, const char *fromname, gboolean from_global, |
||
1618 | char **pf_filename_return, char **pf_to_dir_path_return, char **pf_from_dir_path_return) |
||
1619 | { |
||
1620 | gchar *from_dir; |
||
1621 | gchar *to_dir = g_strdup (get_persconffile_dir(toname)); |
||
1622 | gchar *filename, *from_file, *to_file; |
||
1623 | GList *files, *file; |
||
1624 | |||
1625 | if (from_global) { |
||
1626 | if (strcmp(fromname, DEFAULT_PROFILE) == 0) { |
||
1627 | from_dir = g_strdup (get_global_profiles_dir()); |
||
1628 | } else { |
||
1629 | from_dir = g_strdup_printf ("%s%s%s", get_global_profiles_dir(), G_DIR_SEPARATOR_S, fromname); |
||
1630 | } |
||
1631 | } else { |
||
1632 | from_dir = g_strdup (get_persconffile_dir(fromname)); |
||
1633 | } |
||
1634 | |||
1635 | files = g_hash_table_get_keys(profile_files); |
||
1636 | file = g_list_first(files); |
||
1637 | while (file) { |
||
1638 | filename = (gchar *)file->data; |
||
1639 | from_file = g_strdup_printf ("%s%s%s", from_dir, G_DIR_SEPARATOR_S, filename); |
||
1640 | to_file = g_strdup_printf ("%s%s%s", to_dir, G_DIR_SEPARATOR_S, filename); |
||
1641 | |||
1642 | if (file_exists(from_file) && !copy_file_binary_mode(from_file, to_file)) { |
||
1643 | *pf_filename_return = g_strdup(filename); |
||
1644 | *pf_to_dir_path_return = to_dir; |
||
1645 | *pf_from_dir_path_return = from_dir; |
||
1646 | g_free (from_file); |
||
1647 | g_free (to_file); |
||
1648 | return -1; |
||
1649 | } |
||
1650 | |||
1651 | g_free (from_file); |
||
1652 | g_free (to_file); |
||
1653 | |||
1654 | file = g_list_next(file); |
||
1655 | } |
||
1656 | |||
1657 | g_list_free (files); |
||
1658 | g_free (from_dir); |
||
1659 | g_free (to_dir); |
||
1660 | |||
1661 | return 0; |
||
1662 | } |
||
1663 | |||
1664 | /* |
||
1665 | * Get the (default) directory in which personal data is stored. |
||
1666 | * |
||
1667 | * On Win32, this is the "My Documents" folder in the personal profile. |
||
1668 | * On UNIX this is simply the current directory. |
||
1669 | */ |
||
1670 | /* XXX - should this and the get_home_dir() be merged? */ |
||
1671 | extern const char * |
||
1672 | get_persdatafile_dir(void) |
||
1673 | { |
||
1674 | #ifdef _WIN32 |
||
1675 | TCHAR tszPath[MAX_PATH]; |
||
1676 | |||
1677 | /* Return the cached value, if available */ |
||
1678 | if (persdatafile_dir != NULL) |
||
1679 | return persdatafile_dir; |
||
1680 | |||
1681 | /* |
||
1682 | * Hint: SHGetFolderPath is not available on MSVC 6 - without |
||
1683 | * Platform SDK |
||
1684 | */ |
||
1685 | if (SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE)) { |
||
1686 | persdatafile_dir = g_utf16_to_utf8(tszPath, -1, NULL, NULL, NULL); |
||
1687 | return persdatafile_dir; |
||
1688 | } else { |
||
1689 | return ""; |
||
1690 | } |
||
1691 | #else |
||
1692 | return ""; |
||
1693 | #endif |
||
1694 | } |
||
1695 | |||
1696 | void |
||
1697 | set_persdatafile_dir(const char *p) |
||
1698 | { |
||
1699 | g_free(persdatafile_dir); |
||
1700 | persdatafile_dir = g_strdup(p); |
||
1701 | } |
||
1702 | |||
1703 | #ifdef _WIN32 |
||
1704 | /* |
||
1705 | * Returns the user's home directory on Win32. |
||
1706 | */ |
||
1707 | static const char * |
||
1708 | get_home_dir(void) |
||
1709 | { |
||
1710 | static const char *home = NULL; |
||
1711 | const char *homedrive, *homepath; |
||
1712 | char *homestring; |
||
1713 | char *lastsep; |
||
1714 | |||
1715 | /* Return the cached value, if available */ |
||
1716 | if (home) |
||
1717 | return home; |
||
1718 | |||
1719 | /* |
||
1720 | * XXX - should we use USERPROFILE anywhere in this process? |
||
1721 | * Is there a chance that it might be set but one or more of |
||
1722 | * HOMEDRIVE or HOMEPATH isn't set? |
||
1723 | */ |
||
1724 | homedrive = g_getenv("HOMEDRIVE"); |
||
1725 | if (homedrive != NULL) { |
||
1726 | homepath = g_getenv("HOMEPATH"); |
||
1727 | if (homepath != NULL) { |
||
1728 | /* |
||
1729 | * This is cached, so we don't need to worry about |
||
1730 | * allocating multiple ones of them. |
||
1731 | */ |
||
1732 | homestring = g_strdup_printf("%s%s", homedrive, homepath); |
||
1733 | |||
1734 | /* |
||
1735 | * Trim off any trailing slash or backslash. |
||
1736 | */ |
||
1737 | lastsep = find_last_pathname_separator(homestring); |
||
1738 | if (lastsep != NULL && *(lastsep + 1) == '\0') { |
||
1739 | /* |
||
1740 | * Last separator is the last character |
||
1741 | * in the string. Nuke it. |
||
1742 | */ |
||
1743 | *lastsep = '\0'; |
||
1744 | } |
||
1745 | home = homestring; |
||
1746 | } else |
||
1747 | home = homedrive; |
||
1748 | } else { |
||
1749 | /* |
||
1750 | * Give up and use C:. |
||
1751 | */ |
||
1752 | home = "C:"; |
||
1753 | } |
||
1754 | |||
1755 | return home; |
||
1756 | } |
||
1757 | #endif |
||
1758 | |||
1759 | /* |
||
1760 | * Construct the path name of a personal configuration file, given the |
||
1761 | * file name. |
||
1762 | * |
||
1763 | * On Win32, if "for_writing" is FALSE, we check whether the file exists |
||
1764 | * and, if not, construct a path name relative to the ".wireshark" |
||
1765 | * subdirectory of the user's home directory, and check whether that |
||
1766 | * exists; if it does, we return that, so that configuration files |
||
1767 | * from earlier versions can be read. |
||
1768 | * |
||
1769 | * The returned file name was g_malloc()'d so it must be g_free()d when the |
||
1770 | * caller is done with it. |
||
1771 | */ |
||
1772 | char * |
||
1773 | get_persconffile_path(const char *filename, gboolean from_profile) |
||
1774 | { |
||
1775 | char *path; |
||
1776 | if (do_store_persconffiles && from_profile && !g_hash_table_lookup (profile_files, filename)) { |
||
1777 | /* Store filenames so we know which filenames belongs to a configuration profile */ |
||
1778 | g_hash_table_insert (profile_files, g_strdup(filename), g_strdup(filename)); |
||
1779 | } |
||
1780 | |||
1781 | if (from_profile) { |
||
1782 | path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", |
||
1783 | get_persconffile_dir(persconfprofile), filename); |
||
1784 | } else { |
||
1785 | path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", |
||
1786 | get_persconffile_dir(NULL), filename); |
||
1787 | } |
||
1788 | |||
1789 | return path; |
||
1790 | } |
||
1791 | |||
1792 | /* |
||
1793 | * Construct the path name of a global configuration file, given the |
||
1794 | * file name. |
||
1795 | * |
||
1796 | * The returned file name was g_malloc()'d so it must be g_free()d when the |
||
1797 | * caller is done with it. |
||
1798 | */ |
||
1799 | char * |
||
1800 | get_datafile_path(const char *filename) |
||
1801 | { |
||
1802 | if (running_in_build_directory_flag && |
||
1803 | (!strcmp(filename, "AUTHORS-SHORT") || |
||
1804 | !strcmp(filename, "hosts"))) { |
||
1805 | /* We're running in the build directory and the requested file is a |
||
1806 | * generated (or a test) file. Return the file name in the build |
||
1807 | * directory (not in the source/data directory). |
||
1808 | * (Oh the things we do to keep the source directory pristine...) |
||
1809 | */ |
||
1810 | return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_progfile_dir(), filename); |
||
1811 | } else { |
||
1812 | return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(), filename); |
||
1813 | } |
||
1814 | } |
||
1815 | |||
1816 | /* Get the personal plugin dir */ |
||
1817 | /* Return value is malloced so the caller should g_free() it. */ |
||
1818 | char * |
||
1819 | get_plugins_pers_dir(void) |
||
1820 | { |
||
1821 | return get_persconffile_path(PLUGINS_DIR_NAME, FALSE); |
||
1822 | } |
||
1823 | |||
1824 | /* |
||
1825 | * Return an error message for UNIX-style errno indications on open or |
||
1826 | * create operations. |
||
1827 | */ |
||
1828 | const char * |
||
1829 | file_open_error_message(int err, gboolean for_writing) |
||
1830 | { |
||
1831 | const char *errmsg; |
||
1832 | static char errmsg_errno[1024+1]; |
||
1833 | |||
1834 | switch (err) { |
||
1835 | |||
1836 | case ENOENT: |
||
1837 | if (for_writing) |
||
1838 | errmsg = "The path to the file \"%s\" doesn't exist."; |
||
1839 | else |
||
1840 | errmsg = "The file \"%s\" doesn't exist."; |
||
1841 | break; |
||
1842 | |||
1843 | case EACCES: |
||
1844 | if (for_writing) |
||
1845 | errmsg = "You don't have permission to create or write to the file \"%s\"."; |
||
1846 | else |
||
1847 | errmsg = "You don't have permission to read the file \"%s\"."; |
||
1848 | break; |
||
1849 | |||
1850 | case EISDIR: |
||
1851 | errmsg = "\"%s\" is a directory (folder), not a file."; |
||
1852 | break; |
||
1853 | |||
1854 | case ENOSPC: |
||
1855 | errmsg = "The file \"%s\" could not be created because there is no space left on the file system."; |
||
1856 | break; |
||
1857 | |||
1858 | #ifdef EDQUOT |
||
1859 | case EDQUOT: |
||
1860 | errmsg = "The file \"%s\" could not be created because you are too close to, or over, your disk quota."; |
||
1861 | break; |
||
1862 | #endif |
||
1863 | |||
1864 | case EINVAL: |
||
1865 | errmsg = "The file \"%s\" could not be created because an invalid filename was specified."; |
||
1866 | break; |
||
1867 | |||
1868 | #ifdef ENAMETOOLONG |
||
1869 | case ENAMETOOLONG: |
||
1870 | /* XXX Make sure we truncate on a character boundary. */ |
||
1871 | errmsg = "The file name \"%.80s" UTF8_HORIZONTAL_ELLIPSIS "\" is too long."; |
||
1872 | break; |
||
1873 | #endif |
||
1874 | |||
1875 | case ENOMEM: |
||
1876 | /* |
||
1877 | * The problem probably has nothing to do with how much RAM the |
||
1878 | * user has on their machine, so don't confuse them by saying |
||
1879 | * "memory". The problem is probably either virtual address |
||
1880 | * space or swap space. |
||
1881 | */ |
||
1882 | #if GLIB_SIZEOF_VOID_P == 4 |
||
1883 | /* |
||
1884 | * ILP32; we probably ran out of virtual address space. |
||
1885 | */ |
||
1886 | #define ENOMEM_REASON "it can't be handled by a 32-bit application" |
||
1887 | #else |
||
1888 | /* |
||
1889 | * LP64 or LLP64; we probably ran out of swap space. |
||
1890 | */ |
||
1891 | #if defined(_WIN32) |
||
1892 | /* |
||
1893 | * You need to make the pagefile bigger. |
||
1894 | */ |
||
1895 | #define ENOMEM_REASON "the pagefile is too small" |
||
1896 | #elif defined(__APPLE__) |
||
1897 | /* |
||
1898 | * dynamic_pager couldn't, or wouldn't, create more swap files. |
||
1899 | */ |
||
1900 | #define ENOMEM_REASON "your system ran out of swap file space" |
||
1901 | #else |
||
1902 | /* |
||
1903 | * Either you have a fixed swap partition or a fixed swap file, |
||
1904 | * and it needs to be made bigger. |
||
1905 | * |
||
1906 | * This is UN*X, but it's not OS X, so we assume the user is |
||
1907 | * *somewhat* nerdy. |
||
1908 | */ |
||
1909 | #define ENOMEM_REASON "your system is out of swap space" |
||
1910 | #endif |
||
1911 | #endif /* GLIB_SIZEOF_VOID_P == 4 */ |
||
1912 | if (for_writing) |
||
1913 | errmsg = "The file \"%s\" could not be created because " ENOMEM_REASON "."; |
||
1914 | else |
||
1915 | errmsg = "The file \"%s\" could not be opened because " ENOMEM_REASON "."; |
||
1916 | break; |
||
1917 | |||
1918 | default: |
||
1919 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
1920 | "The file \"%%s\" could not be %s: %s.", |
||
1921 | for_writing ? "created" : "opened", |
||
1922 | g_strerror(err)); |
||
1923 | errmsg = errmsg_errno; |
||
1924 | break; |
||
1925 | } |
||
1926 | return errmsg; |
||
1927 | } |
||
1928 | |||
1929 | /* |
||
1930 | * Return an error message for UNIX-style errno indications on write |
||
1931 | * operations. |
||
1932 | */ |
||
1933 | const char * |
||
1934 | file_write_error_message(int err) |
||
1935 | { |
||
1936 | const char *errmsg; |
||
1937 | static char errmsg_errno[1024+1]; |
||
1938 | |||
1939 | switch (err) { |
||
1940 | |||
1941 | case ENOSPC: |
||
1942 | errmsg = "The file \"%s\" could not be saved because there is no space left on the file system."; |
||
1943 | break; |
||
1944 | |||
1945 | #ifdef EDQUOT |
||
1946 | case EDQUOT: |
||
1947 | errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota."; |
||
1948 | break; |
||
1949 | #endif |
||
1950 | |||
1951 | default: |
||
1952 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
1953 | "An error occurred while writing to the file \"%%s\": %s.", |
||
1954 | g_strerror(err)); |
||
1955 | errmsg = errmsg_errno; |
||
1956 | break; |
||
1957 | } |
||
1958 | return errmsg; |
||
1959 | } |
||
1960 | |||
1961 | |||
1962 | gboolean |
||
1963 | file_exists(const char *fname) |
||
1964 | { |
||
1965 | ws_statb64 file_stat; |
||
1966 | |||
1967 | if (!fname) { |
||
1968 | return FALSE; |
||
1969 | } |
||
1970 | |||
1971 | #if defined(_MSC_VER) && _MSC_VER < 1900 |
||
1972 | |||
1973 | /* |
||
1974 | * This is a bit tricky on win32. The st_ino field is documented as: |
||
1975 | * "The inode, and therefore st_ino, has no meaning in the FAT, ..." |
||
1976 | * but it *is* set to zero if stat() returns without an error, |
||
1977 | * so this is working, but maybe not quite the way expected. ULFL |
||
1978 | */ |
||
1979 | file_stat.st_ino = 1; /* this will make things work if an error occurred */ |
||
1980 | ws_stat64(fname, &file_stat); |
||
1981 | if (file_stat.st_ino == 0) { |
||
1982 | return TRUE; |
||
1983 | } else { |
||
1984 | return FALSE; |
||
1985 | } |
||
1986 | #else |
||
1987 | if (ws_stat64(fname, &file_stat) != 0 && errno == ENOENT) { |
||
1988 | return FALSE; |
||
1989 | } else { |
||
1990 | return TRUE; |
||
1991 | } |
||
1992 | #endif |
||
1993 | } |
||
1994 | |||
1995 | /* |
||
1996 | * Check that the from file is not the same as to file |
||
1997 | * We do it here so we catch all cases ... |
||
1998 | * Unfortunately, the file requester gives us an absolute file |
||
1999 | * name and the read file name may be relative (if supplied on |
||
2000 | * the command line), so we can't just compare paths. From Joerg Mayer. |
||
2001 | */ |
||
2002 | gboolean |
||
2003 | files_identical(const char *fname1, const char *fname2) |
||
2004 | { |
||
2005 | /* Two different implementations, because: |
||
2006 | * |
||
2007 | * - _fullpath is not available on UN*X, so we can't get full |
||
2008 | * paths and compare them (which wouldn't work with hard links |
||
2009 | * in any case); |
||
2010 | * |
||
2011 | * - st_ino isn't filled in with a meaningful value on Windows. |
||
2012 | */ |
||
2013 | #ifdef _WIN32 |
||
2014 | char full1[MAX_PATH], full2[MAX_PATH]; |
||
2015 | |||
2016 | /* |
||
2017 | * Get the absolute full paths of the file and compare them. |
||
2018 | * That won't work if you have hard links, but those aren't |
||
2019 | * much used on Windows, even though NTFS supports them. |
||
2020 | * |
||
2021 | * XXX - will _fullpath work with UNC? |
||
2022 | */ |
||
2023 | if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) { |
||
2024 | return FALSE; |
||
2025 | } |
||
2026 | |||
2027 | if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) { |
||
2028 | return FALSE; |
||
2029 | } |
||
2030 | |||
2031 | if(strcmp(full1, full2) == 0) { |
||
2032 | return TRUE; |
||
2033 | } else { |
||
2034 | return FALSE; |
||
2035 | } |
||
2036 | #else |
||
2037 | ws_statb64 filestat1, filestat2; |
||
2038 | |||
2039 | /* |
||
2040 | * Compare st_dev and st_ino. |
||
2041 | */ |
||
2042 | if (ws_stat64(fname1, &filestat1) == -1) |
||
2043 | return FALSE; /* can't get info about the first file */ |
||
2044 | if (ws_stat64(fname2, &filestat2) == -1) |
||
2045 | return FALSE; /* can't get info about the second file */ |
||
2046 | return (filestat1.st_dev == filestat2.st_dev && |
||
2047 | filestat1.st_ino == filestat2.st_ino); |
||
2048 | #endif |
||
2049 | } |
||
2050 | |||
2051 | /* |
||
2052 | * Copy a file in binary mode, for those operating systems that care about |
||
2053 | * such things. This should be OK for all files, even text files, as |
||
2054 | * we'll copy the raw bytes, and we don't look at the bytes as we copy |
||
2055 | * them. |
||
2056 | * |
||
2057 | * Returns TRUE on success, FALSE on failure. If a failure, it also |
||
2058 | * displays a simple dialog window with the error message. |
||
2059 | */ |
||
2060 | gboolean |
||
2061 | copy_file_binary_mode(const char *from_filename, const char *to_filename) |
||
2062 | { |
||
2063 | int from_fd, to_fd, err; |
||
2064 | ssize_t nread, nwritten; |
||
2065 | guint8 *pd = NULL; |
||
2066 | |||
2067 | /* Copy the raw bytes of the file. */ |
||
2068 | from_fd = ws_open(from_filename, O_RDONLY | O_BINARY, 0000 /* no creation so don't matter */); |
||
2069 | if (from_fd < 0) { |
||
2070 | report_open_failure(from_filename, errno, FALSE); |
||
2071 | goto done; |
||
2072 | } |
||
2073 | |||
2074 | /* Use open() instead of creat() so that we can pass the O_BINARY |
||
2075 | flag, which is relevant on Win32; it appears that "creat()" |
||
2076 | may open the file in text mode, not binary mode, but we want |
||
2077 | to copy the raw bytes of the file, so we need the output file |
||
2078 | to be open in binary mode. */ |
||
2079 | to_fd = ws_open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); |
||
2080 | if (to_fd < 0) { |
||
2081 | report_open_failure(to_filename, errno, TRUE); |
||
2082 | ws_close(from_fd); |
||
2083 | goto done; |
||
2084 | } |
||
2085 | |||
2086 | #define FS_READ_SIZE 65536 |
||
2087 | pd = (guint8 *)g_malloc(FS_READ_SIZE); |
||
2088 | while ((nread = ws_read(from_fd, pd, FS_READ_SIZE)) > 0) { |
||
2089 | nwritten = ws_write(to_fd, pd, nread); |
||
2090 | if (nwritten < nread) { |
||
2091 | if (nwritten < 0) |
||
2092 | err = errno; |
||
2093 | else |
||
2094 | err = WTAP_ERR_SHORT_WRITE; |
||
2095 | report_write_failure(to_filename, err); |
||
2096 | ws_close(from_fd); |
||
2097 | ws_close(to_fd); |
||
2098 | goto done; |
||
2099 | } |
||
2100 | } |
||
2101 | if (nread < 0) { |
||
2102 | err = errno; |
||
2103 | report_read_failure(from_filename, err); |
||
2104 | ws_close(from_fd); |
||
2105 | ws_close(to_fd); |
||
2106 | goto done; |
||
2107 | } |
||
2108 | ws_close(from_fd); |
||
2109 | if (ws_close(to_fd) < 0) { |
||
2110 | report_write_failure(to_filename, errno); |
||
2111 | goto done; |
||
2112 | } |
||
2113 | |||
2114 | g_free(pd); |
||
2115 | pd = NULL; |
||
2116 | return TRUE; |
||
2117 | |||
2118 | done: |
||
2119 | g_free(pd); |
||
2120 | return FALSE; |
||
2121 | } |
||
2122 | |||
2123 | /* |
||
2124 | * Editor modelines |
||
2125 | * |
||
2126 | * Local Variables: |
||
2127 | * c-basic-offset: 4 |
||
2128 | * tab-width: 8 |
||
2129 | * indent-tabs-mode: nil |
||
2130 | * End: |
||
2131 | * |
||
2132 | * ex: set shiftwidth=4 tabstop=8 expandtab: |
||
2133 | * :indentSize=4:tabSize=8:noTabs=true: |
||
2134 | */ |