vppinfra: Add method for getting current executable name

Add a unix method for getting the current executable name. This is
implemented to match the readlink api for existing calls.

Type: improvement
Change-Id: Id06a55892d09d0b305a56b55a424f53ffb685a72
Signed-off-by: Tom Jones <thj@freebsd.org>
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/plugins/fateshare/fateshare.c b/src/plugins/fateshare/fateshare.c
index 33ee167..37cd030 100644
--- a/src/plugins/fateshare/fateshare.c
+++ b/src/plugins/fateshare/fateshare.c
@@ -17,6 +17,7 @@
 
 #include <vnet/vnet.h>
 #include <vnet/plugin/plugin.h>
+#include <vppinfra/unix.h>
 #include <fateshare/fateshare.h>
 
 #include <vlibapi/api.h>
@@ -197,24 +198,30 @@
 
   if (fmp->monitor_cmd == 0)
     {
-      char *p, path[PATH_MAX];
-      int rv;
+      char *p;
+      u8 *path;
 
       /* find executable path */
-      if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
-	return clib_error_return (
-	  0, "could not stat /proc/self/exe - set monitor manually");
+      path = os_get_exec_path ();
 
-      /* readlink doesn't provide null termination */
-      path[rv] = 0;
+      if (path == 0)
+	return clib_error_return (
+	  0, "could not get exec path - set monitor manually");
+
+      /* add null termination */
+      vec_add1 (path, 0);
 
       /* strip filename */
-      if ((p = strrchr (path, '/')) == 0)
-	return clib_error_return (
-	  0, "could not determine vpp directory - set monitor manually");
+      if ((p = strrchr ((char *) path, '/')) == 0)
+	{
+	  vec_free (path);
+	  return clib_error_return (
+	    0, "could not determine vpp directory - set monitor manually");
+	}
       *p = 0;
 
       fmp->monitor_cmd = format (0, "%s/vpp_fateshare_monitor\0", path);
+      vec_free (path);
     }
   if (fmp->monitor_logfile == 0)
     {
diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c
index 38eef41..ee28ca8 100644
--- a/src/vlib/unix/main.c
+++ b/src/vlib/unix/main.c
@@ -39,6 +39,7 @@
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
 #include <vlib/unix/plugin.h>
+#include <vppinfra/unix.h>
 
 #include <limits.h>
 #include <signal.h>
@@ -612,22 +613,23 @@
   vlib_main_t *vm = vlib_get_first_main (); /* one and only time for this! */
   unformat_input_t input;
   clib_error_t *e;
-  char buffer[PATH_MAX];
   int i;
 
   vec_validate_aligned (vgm->vlib_mains, 0, CLIB_CACHE_LINE_BYTES);
 
-  if ((i = readlink ("/proc/self/exe", buffer, sizeof (buffer) - 1)) > 0)
+  vgm->exec_path = (char *) os_get_exec_path ();
+
+  if (vgm->exec_path)
     {
-      int j;
-      buffer[i] = 0;
-      vgm->exec_path = vec_new (char, i + 1);
-      clib_memcpy_fast (vgm->exec_path, buffer, i + 1);
-      for (j = i - 1; j > 0; j--)
-	if (buffer[j - 1] == '/')
+      for (i = vec_len (vgm->exec_path) - 1; i > 0; i--)
+	if (vgm->exec_path[i - 1] == '/')
 	  break;
-      vgm->name = vec_new (char, i - j + 1);
-      clib_memcpy_fast (vgm->name, buffer + j, i - j + 1);
+
+      vgm->name = 0;
+
+      vec_add (vgm->name, vgm->exec_path + i, vec_len (vgm->exec_path) - i);
+      vec_add1 (vgm->exec_path, 0);
+      vec_add1 (vgm->name, 0);
     }
   else
     vgm->exec_path = vgm->name = argv[0];
diff --git a/src/vpp/vnet/main.c b/src/vpp/vnet/main.c
index 71434a9..c57efd5 100644
--- a/src/vpp/vnet/main.c
+++ b/src/vpp/vnet/main.c
@@ -22,6 +22,8 @@
 
 #include <vppinfra/clib.h>
 #include <vppinfra/cpu.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/unix.h>
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
 #include <vlib/threads.h>
@@ -43,25 +45,26 @@
 vpp_find_plugin_path ()
 {
   extern char *vat_plugin_path;
-  char *p, path[PATH_MAX];
-  int rv;
-  u8 *s;
+  char *p;
+  u8 *s, *path;
 
   /* find executable path */
-  if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
+  path = os_get_exec_path ();
+
+  if (!path)
     return;
 
-  /* readlink doesn't provide null termination */
-  path[rv] = 0;
+  /* add null termination */
+  vec_add1 (path, 0);
 
   /* strip filename */
-  if ((p = strrchr (path, '/')) == 0)
-    return;
+  if ((p = strrchr ((char *) path, '/')) == 0)
+    goto done;
   *p = 0;
 
   /* strip bin/ */
-  if ((p = strrchr (path, '/')) == 0)
-    return;
+  if ((p = strrchr ((char *) path, '/')) == 0)
+    goto done;
   *p = 0;
 
   s = format (0, "%s/" CLIB_LIB_DIR "/vpp_plugins", path, path);
@@ -71,6 +74,9 @@
   s = format (0, "%s/" CLIB_LIB_DIR "/vpp_api_test_plugins", path, path);
   vec_add1 (s, 0);
   vat_plugin_path = (char *) s;
+
+done:
+  vec_free (path);
 }
 
 static void
diff --git a/src/vppinfra/unix-misc.c b/src/vppinfra/unix-misc.c
index 4dbc5ce..29cbe0a 100644
--- a/src/vppinfra/unix-misc.c
+++ b/src/vppinfra/unix-misc.c
@@ -42,6 +42,8 @@
 #include <vppinfra/format.h>
 #ifdef __linux__
 #include <vppinfra/linux/sysfs.h>
+#else
+#include <sys/sysctl.h>
 #endif
 
 #include <sys/stat.h>
@@ -358,6 +360,28 @@
 #endif
 }
 
+__clib_export u8 *
+os_get_exec_path ()
+{
+  u8 *rv = 0;
+#ifdef __linux__
+  char tmp[PATH_MAX];
+  ssize_t sz = readlink ("/proc/self/exe", tmp, sizeof (tmp));
+
+  if (sz <= 0)
+    return 0;
+#else
+  char tmp[MAXPATHLEN];
+  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+  size_t sz = MAXPATHLEN;
+
+  if (sysctl (mib, 4, tmp, &sz, NULL, 0) == -1)
+    return 0;
+#endif
+  vec_add (rv, tmp, sz);
+  return rv;
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vppinfra/unix.h b/src/vppinfra/unix.h
index 3ad57b0..abda218 100644
--- a/src/vppinfra/unix.h
+++ b/src/vppinfra/unix.h
@@ -71,6 +71,10 @@
 /* Retrieve physical core id of specific cpu, -1 if not available */
 int os_get_cpu_phys_core_id (int cpu);
 
+/* Retrieve the path of the current executable as a vector (not
+ * null-terminated). */
+u8 *os_get_exec_path ();
+
 #endif /* included_clib_unix_h */
 
 /*