util: Pre-allocate buffer for ovs_lasterror_to_string().
[sliver-openvswitch.git] / lib / util.c
index 9f37350..911cc3e 100644 (file)
@@ -50,11 +50,13 @@ DEFINE_PER_THREAD_MALLOCED_DATA(char *, subprogram_name);
 /* --version option output. */
 static char *program_version;
 
-/* Buffer used by ovs_strerror(). */
+/* Buffer used by ovs_strerror() and ovs_format_message(). */
 DEFINE_STATIC_PER_THREAD_DATA(struct { char s[128]; },
                               strerror_buffer,
                               { "" });
 
+static char *xreadlink(const char *filename);
+
 void
 ovs_assert_failure(const char *where, const char *function,
                    const char *condition)
@@ -67,7 +69,7 @@ ovs_assert_failure(const char *where, const char *function,
     case 0:
         VLOG_ABORT("%s: assertion %s failed in %s()",
                    where, condition, function);
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case 1:
         fprintf(stderr, "%s: assertion %s failed in %s()",
@@ -323,6 +325,10 @@ ovs_retval_to_string(int retval)
             : ovs_strerror(retval));
 }
 
+/* This function returns the string describing the error number in 'error'
+ * for POSIX platforms.  For Windows, this function can be used for C library
+ * calls.  For socket calls that are also used in Windows, use sock_strerror()
+ * instead.  For WINAPI calls, look at ovs_lasterror_to_string(). */
 const char *
 ovs_strerror(int error)
 {
@@ -373,11 +379,22 @@ void
 set_program_name__(const char *argv0, const char *version, const char *date,
                    const char *time)
 {
-    const char *slash = strrchr(argv0, '/');
+#ifdef _WIN32
+    char *basename;
+    size_t max_len = strlen(argv0) + 1;
 
+    if (program_name) {
+        return;
+    }
+    basename = xmalloc(max_len);
+    _splitpath_s(argv0, NULL, 0, NULL, 0, basename, max_len, NULL, 0);
+    assert_single_threaded();
+    program_name = basename;
+#else
+    const char *slash = strrchr(argv0, '/');
     assert_single_threaded();
-
     program_name = slash ? slash + 1 : argv0;
+#endif
 
     free(program_version);
 
@@ -730,7 +747,7 @@ abs_file_name(const char *dir, const char *file_name)
 /* Like readlink(), but returns the link name as a null-terminated string in
  * allocated memory that the caller must eventually free (with free()).
  * Returns NULL on error, in which case errno is set appropriately. */
-char *
+static char *
 xreadlink(const char *filename)
 {
     size_t size;
@@ -762,10 +779,14 @@ xreadlink(const char *filename)
  *
  *     - Only symlinks in the final component of 'filename' are dereferenced.
  *
+ * For Windows platform, this function returns a string that has the same
+ * value as the passed string.
+ *
  * The caller must eventually free the returned string (with free()). */
 char *
 follow_symlinks(const char *filename)
 {
+#ifndef _WIN32
     struct stat s;
     char *fn;
     int i;
@@ -810,6 +831,7 @@ follow_symlinks(const char *filename)
 
     VLOG_WARN("%s: too many levels of symlinks", filename);
     free(fn);
+#endif
     return xstrdup(filename);
 }
 
@@ -1360,7 +1382,7 @@ scan_float(const char *s, const struct scan_spec *spec, va_list *args)
     case SCAN_INTMAX_T:
     case SCAN_PTRDIFF_T:
     case SCAN_SIZE_T:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
     return s;
 }
@@ -1642,3 +1664,24 @@ exit:
     return ok;
 }
 
+#ifdef _WIN32
+\f
+char *
+ovs_format_message(int error)
+{
+    enum { BUFSIZE = sizeof strerror_buffer_get()->s };
+    char *buffer = strerror_buffer_get()->s;
+
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                  NULL, error, 0, buffer, BUFSIZE, NULL);
+    return buffer;
+}
+
+/* Returns a null-terminated string that explains the last error.
+ * Use this function to get the error string for WINAPI calls. */
+char *
+ovs_lasterror_to_string(void)
+{
+    return ovs_format_message(GetLastError());
+}
+#endif