Free the string you "g_strdup()"ed, rather than handing "g_free()" the
[obnox/wireshark/wip.git] / util.c
diff --git a/util.c b/util.c
index d05cc4cd6744bd3ba14acfe44cea5d15f3b93855..e7f23accec91cf7cfcd1fd6b0632333eaf4f9c3d 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,7 +1,7 @@
 /* util.c
  * Utility routines
  *
- * $Id: util.c,v 1.38 2000/03/14 08:26:19 guy Exp $
+ * $Id: util.c,v 1.51 2001/04/02 09:53:43 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 #endif
 
 #ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-#  include <stdarg.h>
-# else
-#  include <varargs.h>
-# endif
 # include "snprintf.h"
 #endif
 
@@ -80,7 +75,9 @@ typedef int mode_t;   /* for win32 */
 #include <sys/ioctl.h>
 #endif
 
-#ifdef HAVE_NET_IF_H
+#include <pcap.h>
+
+#ifndef WIN32
 #include <net/if.h>
 #endif
 
@@ -93,94 +90,48 @@ typedef int mode_t; /* for win32 */
 #endif
 
 /*
- * Given a pathname, return a pointer to the last pathname separator
- * character in the pathname, or NULL if the pathname contains no
- * separators.
+ * Given a pathname, return:
+ *
+ *     the errno, if an attempt to "stat()" the file fails;
+ *
+ *     EISDIR, if the attempt succeeded and the file turned out
+ *     to be a directory;
+ *
+ *     0, if the attempt succeeded and the file turned out not
+ *     to be a directory.
  */
-static char *
-find_last_pathname_separator(char *path)
-{
-       char *separator;
-
-#ifdef WIN32
-       char c;
-
-       /*
-        * We have to scan for '\' or '/'.
-        * Get to the end of the string.
-        */
-       separator = path + strlen(path);        /* points to ending '\0' */
-       while (separator > path) {
-               c = *--separator;
-               if (c == '\\' || c == '/')
-                       return separator;       /* found it */
-       }
-
-       /*
-        * OK, we didn't find any, so no directories - but there might
-        * be a drive letter....
-        */
-       return strchr(path, ':');
-#else
-       separator = strrchr(path, '/');
-#endif
-       return separator;
-}
 
 /*
- * Given a pathname, return the last component.
+ * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
+ * define them either.)
+ *
+ * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
  */
-char *
-get_basename(char *path)
-{
-       char *filename;
-
-       filename = find_last_pathname_separator(path);
-       if (filename == NULL) {
-               /*
-                * There're no directories, drive letters, etc. in the
-                * name; the pathname *is* the file name.
-                */
-               filename = path;
-       } else {
-               /*
-                * Skip past the pathname or drive letter separator.
-                */
-               filename++;
-       }
-       return filename;
-}
+#ifndef S_ISREG
+#define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO        _S_IFIFO
+#endif
+#ifndef S_ISFIFO
+#define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
+#endif
 
-/*
- * Given a pathname, return a string containing everything but the
- * last component.  NOTE: this overwrites the pathname handed into
- * it....
- */
-char *
-get_dirname(char *path)
+int
+test_for_directory(const char *path)
 {
-       char *separator;
+       struct stat statb;
 
-       separator = find_last_pathname_separator(path);
-       if (separator == NULL) {
-               /*
-                * There're no directories, drive letters, etc. in the
-                * name; there is no directory path to return.
-                */
-               return NULL;
-       }
-
-       /*
-        * Get rid of the last pathname separator and the final file
-        * name following it.
-        */
-       *separator = '\0';
+       if (stat(path, &statb) < 0)
+               return errno;
 
-       /*
-        * "path" now contains the pathname of the directory containing
-        * the file/directory to which it referred.
-        */
-       return path;
+       if (S_ISDIR(statb.st_mode))
+               return EISDIR;
+       else
+               return 0;
 }
 
 /*
@@ -468,6 +419,8 @@ get_interface_list(int *err, char *err_str)
        int     sock = socket(AF_INET, SOCK_DGRAM, 0);
        struct search_user_data user_data;
        pcap_t *pch;
+       int len, lastlen;
+       char *buf;
 
        if (sock < 0) {
                sprintf(err_str, "Error opening socket: %s",
@@ -476,19 +429,36 @@ get_interface_list(int *err, char *err_str)
        }
 
        /*
-        * Since we have to grab the interface list all at once, we'll
-        * make plenty of room.
+        * This code came from: W. Richard Stevens: "UNIX Network Programming",
+        * Networking APIs: Sockets and XTI, Vol 1, page 434.
         */
-       ifc.ifc_len = 1024 * sizeof(struct ifreq);
-       ifc.ifc_buf = malloc(ifc.ifc_len);
-
-       if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ||
-           ifc.ifc_len < sizeof(struct ifreq)) {
-               sprintf(err_str, "SIOCGIFCONF error getting list of interfaces: %s",
-                   strerror(errno));
-               goto fail;
-        }
-
+       lastlen = 0;
+       len = 100 * sizeof(struct ifreq);
+       for ( ; ; ) {
+               buf = g_malloc(len);
+               ifc.ifc_len = len;
+               ifc.ifc_buf = buf;
+               memset (buf, 0, len);
+               if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+                       if (errno != EINVAL || lastlen != 0) {
+                               sprintf(err_str,
+                                       "SIOCGIFCONF ioctl error getting list of interfaces: %s",
+                                       strerror(errno));
+                               goto fail;
+                       }
+               } else {
+                       if (ifc.ifc_len < sizeof(struct ifreq)) {
+                               sprintf(err_str,
+                                       "SIOCGIFCONF ioctl gave too small return buffer");
+                               goto fail;
+                       }
+                       if (ifc.ifc_len == lastlen)
+                               break;                  /* success, len has not changed */
+                       lastlen = ifc.ifc_len;
+               }
+               len += 10 * sizeof(struct ifreq);       /* increment */
+               g_free(buf);
+       }
        ifr = (struct ifreq *) ifc.ifc_req;
        last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
        while (ifr < last) {
@@ -573,7 +543,24 @@ get_interface_list(int *err, char *err_str)
 #endif
        }
 
-       free(ifc.ifc_buf);
+#ifdef linux
+       /*
+        * OK, maybe we have support for the "any" device, to do a cooked
+        * capture on all interfaces at once.
+        * Try opening it and, if that succeeds, add it to the end of
+        * the list of interfaces.
+        */
+       pch = pcap_open_live("any", MIN_PACKET_SIZE, 0, 0, err_str);
+       if (pch != NULL) {
+               /*
+                * It worked; we can use the "any" device.
+                */
+               il = g_list_insert(il, g_strdup("any"), -1);
+               pcap_close(pch);
+       }
+#endif
+
+       g_free(ifc.ifc_buf);
        close(sock);
 
        if (il == NULL) {
@@ -589,7 +576,7 @@ fail:
                g_list_foreach(il, free_if_cb, NULL);
                g_list_free(il);
        }
-       free(ifc.ifc_buf);
+       g_free(ifc.ifc_buf);
        close(sock);
        *err = CANT_GET_INTERFACE_LIST;
        return NULL;
@@ -608,25 +595,46 @@ GList *
 get_interface_list(int *err, char *err_str) {
   GList  *il = NULL;
   wchar_t *names;
+  char *win95names; 
   char newname[255];
   int i, j, done;
   
   names = (wchar_t *)pcap_lookupdev(err_str);
   i = done = 0;
 
-  if (names)
-     do
-     {
-        j = 0;
-        while (names[i] != 0)
-           newname[j++] = names[i++];
-        i++;
-        if (names[i] == 0)
-           done = 1;
-        newname[j++] = 0;
-        il = g_list_append(il, g_strdup(newname));
-     } while (!done);
-  
+  if (names) {
+         if (names[0]<256) { 
+                 /* If names[0] is less than 256 it means the first byte is 0
+                    This implies that we are using unicode characters */
+                 do 
+                 { 
+                         j = 0; 
+                         while (names[i] != 0) 
+                                 newname[j++] = names[i++]; 
+                         i++; 
+                         if (names[i] == 0) 
+                                 done = 1; 
+                         newname[j++] = 0; 
+                         il = g_list_append(il, g_strdup(newname)); 
+                 } while (!done); 
+         } 
+         else { 
+                 /* Otherwise we are in Windows 95/98 and using ascii(8 bit)
+                    characters */
+                 do 
+                 { 
+                         win95names=(char *)names; 
+                         j = 0; 
+                         while (win95names[i] != 0) 
+                                 newname[j++] = win95names[i++]; 
+                         i++; 
+                         if (win95names[i] == 0) 
+                                 done = 1; 
+                         newname[j++] = 0; 
+                         il = g_list_append(il, g_strdup(newname)); 
+                 } while (!done); 
+         } 
+  }
   return(il);
 }
 #endif
@@ -648,79 +656,47 @@ free_interface_list(GList *if_list)
 
 #endif /* HAVE_LIBPCAP */
 
-const char*
-get_home_dir(void)
-{
-       static const char *home = NULL;
-#ifdef WIN32
-       char *homedrive, *homepath;
-       char *homestring;
-       char *lastsep;
-#else
-       struct passwd *pwd;
-#endif
-
-       /* Return the cached value, if available */
-       if (home)
-               return home;
-#ifdef WIN32
-       /*
-        * XXX - should we use USERPROFILE anywhere in this process?
-        * Is there a chance that it might be set but one or more of
-        * HOMEDRIVE or HOMEPATH isn't set?
-        */
-       homedrive = getenv("HOMEDRIVE");
-       if (homedrive != NULL) {
-               homepath = getenv("HOMEPATH");
-               if (homepath != NULL) {
-                       /*
-                        * This is cached, so we don't need to worry about
-                        * allocating multiple ones of them.
-                        */
-                       homestring =
-                           g_malloc(strlen(homedrive) + strlen(homepath) + 1);
-                       strcpy(homestring, homedrive);
-                       strcat(homestring, homepath);
-
-                       /*
-                        * Trim off any trailing slash or backslash.
-                        */
-                       lastsep = find_last_pathname_separator(homestring);
-                       if (lastsep != NULL && *(lastsep + 1) == '\0') {
-                               /*
-                                * Last separator is the last character
-                                * in the string.  Nuke it.
-                                */
-                               *lastsep = '\0';
-                       }
-                       home = homestring;
-               } else
-                       home = homedrive;
-       } else {
-               /*
-                * Try using "windir?
-                */
-               home = "C:";
-       }
-#else
-       home = getenv("HOME");
-       if (home == NULL) {
-               /*
-                * Get their home directory from the password file.
-                * If we can't even find a password file entry for them,
-                * use "/tmp".
-                */
-               pwd = getpwuid(getuid());
-               if (pwd != NULL) {
-                       /*
-                        * This is cached, so we don't need to worry
-                        * about allocating multiple ones of them.
-                        */
-                       home = g_strdup(pwd->pw_dir);
-               } else
-                       home = "/tmp";
-       }
-#endif
 
-       return home;
+/* Compute the difference between two seconds/microseconds time stamps. */
+void
+compute_timestamp_diff(gint *diffsec, gint *diffusec,
+       guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
+{
+  if (sec1 == sec2) {
+    /* The seconds part of the first time is the same as the seconds
+       part of the second time, so if the microseconds part of the first
+       time is less than the microseconds part of the second time, the
+       first time is before the second time.  The microseconds part of
+       the delta should just be the difference between the microseconds
+       part of the first time and the microseconds part of the second
+       time; don't adjust the seconds part of the delta, as it's OK if
+       the microseconds part is negative. */
+
+    *diffsec = sec1 - sec2;
+    *diffusec = usec1 - usec2;
+  } else if (sec1 <= sec2) {
+    /* The seconds part of the first time is less than the seconds part
+       of the second time, so the first time is before the second time.
+
+       Both the "seconds" and "microseconds" value of the delta
+       should have the same sign, so if the difference between the
+       microseconds values would be *positive*, subtract 1,000,000
+       from it, and add one to the seconds value. */
+    *diffsec = sec1 - sec2;
+    if (usec2 >= usec1) {
+      *diffusec = usec1 - usec2;
+    } else {
+      *diffusec = (usec1 - 1000000) - usec2;
+      (*diffsec)++;
+    }
+  } else {
+    /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
+    *diffsec = sec1 - sec2;
+    if (usec2 <= usec1) {
+      *diffusec = usec1 - usec2;
+    } else {
+      *diffusec = (usec1 + 1000000) - usec2;
+      (*diffsec)--;
+    }
+  }
 }