On Windows, when getting the user's home directory, don't look at the
[obnox/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id: util.c,v 1.38 2000/03/14 08:26:19 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <errno.h>
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h>
43 #endif
44
45 #ifdef HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48
49 #ifdef NEED_SNPRINTF_H
50 # ifdef HAVE_STDARG_H
51 #  include <stdarg.h>
52 # else
53 #  include <varargs.h>
54 # endif
55 # include "snprintf.h"
56 #endif
57
58 #ifndef WIN32
59 #include <pwd.h>
60 #endif
61
62 #ifdef NEED_MKSTEMP
63 #include "mkstemp.h"
64 #endif
65
66 #include "util.h"
67
68 #ifdef HAVE_IO_H
69 #include <io.h>
70 typedef int mode_t;     /* for win32 */
71 #endif
72
73 #ifdef HAVE_LIBPCAP
74
75 #ifdef HAVE_SYS_SOCKET_H
76 #include <sys/socket.h>
77 #endif
78
79 #ifdef HAVE_SYS_IOCTL_H
80 #include <sys/ioctl.h>
81 #endif
82
83 #ifdef HAVE_NET_IF_H
84 #include <net/if.h>
85 #endif
86
87 #ifdef HAVE_SYS_SOCKIO_H
88 # include <sys/sockio.h>
89 #endif
90
91 #include "globals.h"
92
93 #endif
94
95 /*
96  * Given a pathname, return a pointer to the last pathname separator
97  * character in the pathname, or NULL if the pathname contains no
98  * separators.
99  */
100 static char *
101 find_last_pathname_separator(char *path)
102 {
103         char *separator;
104
105 #ifdef WIN32
106         char c;
107
108         /*
109          * We have to scan for '\' or '/'.
110          * Get to the end of the string.
111          */
112         separator = path + strlen(path);        /* points to ending '\0' */
113         while (separator > path) {
114                 c = *--separator;
115                 if (c == '\\' || c == '/')
116                         return separator;       /* found it */
117         }
118
119         /*
120          * OK, we didn't find any, so no directories - but there might
121          * be a drive letter....
122          */
123         return strchr(path, ':');
124 #else
125         separator = strrchr(path, '/');
126 #endif
127         return separator;
128 }
129
130 /*
131  * Given a pathname, return the last component.
132  */
133 char *
134 get_basename(char *path)
135 {
136         char *filename;
137
138         filename = find_last_pathname_separator(path);
139         if (filename == NULL) {
140                 /*
141                  * There're no directories, drive letters, etc. in the
142                  * name; the pathname *is* the file name.
143                  */
144                 filename = path;
145         } else {
146                 /*
147                  * Skip past the pathname or drive letter separator.
148                  */
149                 filename++;
150         }
151         return filename;
152 }
153
154 /*
155  * Given a pathname, return a string containing everything but the
156  * last component.  NOTE: this overwrites the pathname handed into
157  * it....
158  */
159 char *
160 get_dirname(char *path)
161 {
162         char *separator;
163
164         separator = find_last_pathname_separator(path);
165         if (separator == NULL) {
166                 /*
167                  * There're no directories, drive letters, etc. in the
168                  * name; there is no directory path to return.
169                  */
170                 return NULL;
171         }
172
173         /*
174          * Get rid of the last pathname separator and the final file
175          * name following it.
176          */
177         *separator = '\0';
178
179         /*
180          * "path" now contains the pathname of the directory containing
181          * the file/directory to which it referred.
182          */
183         return path;
184 }
185
186 /*
187  * Collect command-line arguments as a string consisting of the arguments,
188  * separated by spaces.
189  */
190 char *
191 get_args_as_string(int argc, char **argv, int optind)
192 {
193         int len;
194         int i;
195         char *argstring;
196
197         /*
198          * Find out how long the string will be.
199          */
200         len = 0;
201         for (i = optind; i < argc; i++) {
202                 len += strlen(argv[i]);
203                 len++;  /* space, or '\0' if this is the last argument */
204         }
205
206         /*
207          * Allocate the buffer for the string.
208          */
209         argstring = g_malloc(len);
210
211         /*
212          * Now construct the string.
213          */
214         strcpy(argstring, "");
215         i = optind;
216         for (;;) {
217                 strcat(argstring, argv[i]);
218                 i++;
219                 if (i == argc)
220                         break;
221                 strcat(argstring, " ");
222         }
223         return argstring;
224 }
225
226 static char *
227 setup_tmpdir(char *dir)
228 {
229         int len = strlen(dir);
230         char *newdir;
231
232         /* Append slash if necessary */
233         if (dir[len - 1] == '/') {
234                 newdir = dir;
235         }
236         else {
237                 newdir = g_malloc(len + 2);
238                 strcpy(newdir, dir);
239                 strcat(newdir, "/");
240         }
241         return newdir;
242 }
243
244 static int
245 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
246 {
247         static const char suffix[] = "XXXXXXXXXX";
248         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
249         mode_t old_umask;
250         int tmp_fd;
251
252         if (namebuflen < namelen) {
253                 /* Stick in a truncated name, so that if this error is
254                    reported with the file name, you at least get
255                    something. */
256                 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
257                 errno = ENAMETOOLONG;
258                 return -1;
259         }
260         strcpy(namebuf, dir);
261         strcat(namebuf, pfx);
262         strcat(namebuf, suffix);
263
264         /* The Single UNIX Specification doesn't say that "mkstemp()"
265            creates the temporary file with mode rw-------, so we
266            won't assume that all UNIXes will do so; instead, we set
267            the umask to 0077 to take away all group and other
268            permissions, attempt to create the file, and then put
269            the umask back. */
270         old_umask = umask(0077);
271         tmp_fd = mkstemp(namebuf);
272         umask(old_umask);
273         return tmp_fd;
274 }
275
276 static char *tmpdir = NULL;
277 #ifdef WIN32
278 static char *temp = NULL;
279 #endif
280 static char *E_tmpdir;
281
282 #ifndef P_tmpdir
283 #define P_tmpdir "/var/tmp"
284 #endif
285
286 int
287 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
288 {
289         char *dir;
290         int fd;
291         static gboolean initialized;
292
293         if (!initialized) {
294                 if ((dir = getenv("TMPDIR")) != NULL)
295                         tmpdir = setup_tmpdir(dir);
296 #ifdef WIN32
297                 if ((dir = getenv("TEMP")) != NULL)
298                         temp = setup_tmpdir(dir);
299 #endif
300
301                 E_tmpdir = setup_tmpdir(P_tmpdir);
302                 initialized = TRUE;
303         }
304
305         if (tmpdir != NULL) {
306                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
307                 if (fd != -1)
308                         return fd;
309         }
310
311 #ifdef WIN32
312         if (temp != NULL) {
313                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
314                 if (fd != -1)
315                         return fd;
316         }
317 #endif
318
319         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
320         if (fd != -1)
321                 return fd;
322
323         return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
324 }
325
326 /* ASCII/EBCDIC conversion tables from
327  * http://www.room42.com/store/computer_center/code_tables.shtml
328  */
329 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
330     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
331     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
332     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
333     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
334     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
335     0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
336     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
337     0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
338     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
339     0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
340     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
341     0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
342     0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
343     0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
344     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
345     0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
346     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
347     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
348     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
349     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
350     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
351     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
352     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
353     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
354     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
355     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
356     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
357     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
358     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
359     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
360     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
361     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
362 };
363
364 void
365 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
366 {
367         guint   i;
368         guint8  *bufptr;
369
370         bufptr = buf;
371
372         for (i = 0; i < bytes; i++, bufptr++) {
373                 *bufptr = ASCII_translate_EBCDIC[*bufptr];
374         }
375 }
376
377 guint8
378 ASCII_to_EBCDIC1(guint8 c)
379 {
380         return ASCII_translate_EBCDIC[c];
381 }
382
383 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
384     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
385     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
386     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
387     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
388     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
389     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
390     0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
391     0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
392     0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
393     0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
394     0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
395     0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
396     0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
397     0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
398     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
399     0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
400     0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
401     0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
402     0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
403     0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
404     0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
405     0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
406     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
407     0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
408     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
409     0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
410     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,                                             
411     0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
412     0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
413     0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
414     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,                 
415     0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
416 };
417
418 void
419 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
420 {
421         guint   i;
422         guint8  *bufptr;
423
424         bufptr = buf;
425
426         for (i = 0; i < bytes; i++, bufptr++) {
427                 *bufptr = EBCDIC_translate_ASCII[*bufptr];
428         }
429 }
430
431 guint8
432 EBCDIC_to_ASCII1(guint8 c)
433 {
434         return EBCDIC_translate_ASCII[c];
435 }
436
437 #ifdef HAVE_LIBPCAP
438
439 /*
440  * If the ability to capture packets is added to Wiretap, these
441  * routines should be moved to the Wiretap source (with
442  * "get_interface_list()" and "free_interface_list()" renamed to
443  * "wtap_get_interface_list()" and "wtap_free_interface_list()",
444  * and modified to use Wiretap routines to attempt to open the
445  * interface.
446  */
447
448 struct search_user_data {
449         char    *name;
450         int     found;
451 };
452
453 static void
454 search_for_if_cb(gpointer data, gpointer user_data);
455
456 static void
457 free_if_cb(gpointer data, gpointer user_data);
458
459 #ifndef WIN32
460 GList *
461 get_interface_list(int *err, char *err_str)
462 {
463         GList  *il = NULL;
464         gint    nonloopback_pos = 0;
465         struct  ifreq *ifr, *last;
466         struct  ifconf ifc;
467         struct  ifreq ifrflags;
468         int     sock = socket(AF_INET, SOCK_DGRAM, 0);
469         struct search_user_data user_data;
470         pcap_t *pch;
471
472         if (sock < 0) {
473                 sprintf(err_str, "Error opening socket: %s",
474                     strerror(errno));
475                 return NULL;
476         }
477
478         /*
479          * Since we have to grab the interface list all at once, we'll
480          * make plenty of room.
481          */
482         ifc.ifc_len = 1024 * sizeof(struct ifreq);
483         ifc.ifc_buf = malloc(ifc.ifc_len);
484
485         if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ||
486             ifc.ifc_len < sizeof(struct ifreq)) {
487                 sprintf(err_str, "SIOCGIFCONF error getting list of interfaces: %s",
488                     strerror(errno));
489                 goto fail;
490          }
491
492         ifr = (struct ifreq *) ifc.ifc_req;
493         last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
494         while (ifr < last) {
495                 /*
496                  * Skip addresses that begin with "dummy", or that include
497                  * a ":" (the latter are Solaris virtuals).
498                  */
499                 if (strncmp(ifr->ifr_name, "dummy", 5) == 0 ||
500                     strchr(ifr->ifr_name, ':') != NULL)
501                         goto next;
502
503                 /*
504                  * If we already have this interface name on the list,
505                  * don't add it (SIOCGIFCONF returns, at least on
506                  * BSD-flavored systems, one entry per interface *address*;
507                  * if an interface has multiple addresses, we get multiple
508                  * entries for it).
509                  */
510                 user_data.name = ifr->ifr_name;
511                 user_data.found = FALSE;
512                 g_list_foreach(il, search_for_if_cb, &user_data);
513                 if (user_data.found)
514                         goto next;
515
516                 /*
517                  * Get the interface flags.
518                  */
519                 memset(&ifrflags, 0, sizeof ifrflags);
520                 strncpy(ifrflags.ifr_name, ifr->ifr_name,
521                     sizeof ifrflags.ifr_name);
522                 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
523                         if (errno == ENXIO)
524                                 goto next;
525                         sprintf(err_str, "SIOCGIFFLAGS error getting flags for interface %s: %s",
526                             ifr->ifr_name, strerror(errno));
527                         goto fail;
528                 }
529
530                 /*
531                  * Skip interfaces that aren't up.
532                  */
533                 if (!(ifrflags.ifr_flags & IFF_UP))
534                         goto next;
535
536                 /*
537                  * Skip interfaces that we can't open with "libpcap".
538                  * Open with the minimum packet size - it appears that the
539                  * IRIX SIOCSNOOPLEN "ioctl" may fail if the capture length
540                  * supplied is too large, rather than just truncating it.
541                  */
542                 pch = pcap_open_live(ifr->ifr_name, MIN_PACKET_SIZE, 0, 0,
543                     err_str);
544                 if (pch == NULL)
545                         goto next;
546                 pcap_close(pch);
547
548                 /*
549                  * If it's a loopback interface, add it at the end of the
550                  * list, otherwise add it after the last non-loopback
551                  * interface, so all loopback interfaces go at the end - we
552                  * don't want a loopback interface to be the default capture
553                  * device unless there are no non-loopback devices.
554                  */
555                 if ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
556                     strncmp(ifr->ifr_name, "lo", 2) == 0)
557                         il = g_list_insert(il, g_strdup(ifr->ifr_name), -1);
558                 else {
559                         il = g_list_insert(il, g_strdup(ifr->ifr_name),
560                             nonloopback_pos);
561                         /*
562                          * Insert the next non-loopback interface after this
563                          * one.
564                          */
565                         nonloopback_pos++;
566                 }
567
568         next:
569 #ifdef HAVE_SA_LEN
570                 ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
571 #else
572                 ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
573 #endif
574         }
575
576         free(ifc.ifc_buf);
577         close(sock);
578
579         if (il == NULL) {
580                 /*
581                  * No interfaces found.
582                  */
583                 *err = NO_INTERFACES_FOUND;
584         }
585         return il;
586
587 fail:
588         if (il != NULL) {
589                 g_list_foreach(il, free_if_cb, NULL);
590                 g_list_free(il);
591         }
592         free(ifc.ifc_buf);
593         close(sock);
594         *err = CANT_GET_INTERFACE_LIST;
595         return NULL;
596 }
597
598 static void
599 search_for_if_cb(gpointer data, gpointer user_data)
600 {
601         struct search_user_data *search_user_data = user_data;
602
603         if (strcmp((char *)data, search_user_data->name) == 0)
604                 search_user_data->found = TRUE;
605 }
606 #else
607 GList *
608 get_interface_list(int *err, char *err_str) {
609   GList  *il = NULL;
610   wchar_t *names;
611   char newname[255];
612   int i, j, done;
613   
614   names = (wchar_t *)pcap_lookupdev(err_str);
615   i = done = 0;
616
617   if (names)
618      do
619      {
620         j = 0;
621         while (names[i] != 0)
622            newname[j++] = names[i++];
623         i++;
624         if (names[i] == 0)
625            done = 1;
626         newname[j++] = 0;
627         il = g_list_append(il, g_strdup(newname));
628      } while (!done);
629   
630   return(il);
631 }
632 #endif
633
634 static void
635 free_if_cb(gpointer data, gpointer user_data)
636 {
637         g_free(data);
638 }
639
640 void
641 free_interface_list(GList *if_list)
642 {
643         while (if_list != NULL) {
644                 g_free(if_list->data);
645                 if_list = g_list_remove_link(if_list, if_list);
646         }
647 }
648
649 #endif /* HAVE_LIBPCAP */
650
651 const char*
652 get_home_dir(void)
653 {
654         static const char *home = NULL;
655 #ifdef WIN32
656         char *homedrive, *homepath;
657         char *homestring;
658         char *lastsep;
659 #else
660         struct passwd *pwd;
661 #endif
662
663         /* Return the cached value, if available */
664         if (home)
665                 return home;
666 #ifdef WIN32
667         /*
668          * XXX - should we use USERPROFILE anywhere in this process?
669          * Is there a chance that it might be set but one or more of
670          * HOMEDRIVE or HOMEPATH isn't set?
671          */
672         homedrive = getenv("HOMEDRIVE");
673         if (homedrive != NULL) {
674                 homepath = getenv("HOMEPATH");
675                 if (homepath != NULL) {
676                         /*
677                          * This is cached, so we don't need to worry about
678                          * allocating multiple ones of them.
679                          */
680                         homestring =
681                             g_malloc(strlen(homedrive) + strlen(homepath) + 1);
682                         strcpy(homestring, homedrive);
683                         strcat(homestring, homepath);
684
685                         /*
686                          * Trim off any trailing slash or backslash.
687                          */
688                         lastsep = find_last_pathname_separator(homestring);
689                         if (lastsep != NULL && *(lastsep + 1) == '\0') {
690                                 /*
691                                  * Last separator is the last character
692                                  * in the string.  Nuke it.
693                                  */
694                                 *lastsep = '\0';
695                         }
696                         home = homestring;
697                 } else
698                         home = homedrive;
699         } else {
700                 /*
701                  * Try using "windir?
702                  */
703                 home = "C:";
704         }
705 #else
706         home = getenv("HOME");
707         if (home == NULL) {
708                 /*
709                  * Get their home directory from the password file.
710                  * If we can't even find a password file entry for them,
711                  * use "/tmp".
712                  */
713                 pwd = getpwuid(getuid());
714                 if (pwd != NULL) {
715                         /*
716                          * This is cached, so we don't need to worry
717                          * about allocating multiple ones of them.
718                          */
719                         home = g_strdup(pwd->pw_dir);
720                 } else
721                         home = "/tmp";
722         }
723 #endif
724
725         return home;
726 }