[glib: 1/2] Check for /proc/self/cmdline



commit 4c038a27ff14170141f62f3ab61a6fa7c4747f09
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date:   Wed Mar 20 21:19:29 2019 +0000

    Check for /proc/self/cmdline
    
    Instead of hardcoding /proc/self/cmdline use for __linux__ only,
    do a configure-time test for it.
    
    Specifically, this enables /proc/self/cmdline use on Cygwin.
    
    The configure-time test is very primitive (just tests that the
    file exists and that it's possible to read more than one byte from it),
    relying on the testsuite for more extensive checks.
    
    The test in the testsuite is modified to always run, even on platforms
    where it isn't supposed to pass. If it fails there, the testing framework
    skips it. If the test unexpectedly passes, that is reported too.

 glib/goption.c            |  2 +-
 glib/tests/option-argv0.c | 58 +++++++++++++++++++++++++++++++++++++++++------
 meson.build               | 47 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+), 8 deletions(-)
---
diff --git a/glib/goption.c b/glib/goption.c
index 620595118..8494ca739 100644
--- a/glib/goption.c
+++ b/glib/goption.c
@@ -1815,7 +1815,7 @@ free_pending_nulls (GOptionContext *context,
 static char *
 platform_get_argv0 (void)
 {
-#if defined __linux
+#ifdef HAVE_PROC_SELF_CMDLINE
   char *cmdline;
   char *base_arg0;
   gsize len;
diff --git a/glib/tests/option-argv0.c b/glib/tests/option-argv0.c
index 8ae00ca6f..199eac17c 100644
--- a/glib/tests/option-argv0.c
+++ b/glib/tests/option-argv0.c
@@ -21,13 +21,13 @@
  * Authors: Colin Walters <walters verbum org>
  */
 
+#include "config.h"
 #include <glib.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-#if defined __linux || defined __OpenBSD__
 static void
 test_platform_argv0 (void)
 {
@@ -36,19 +36,65 @@ test_platform_argv0 (void)
   GOptionEntry entries [] =
     { { "test", 't', 0, G_OPTION_ARG_STRING, &arg, NULL, NULL },
       { NULL } };
+  const gchar * const expected_prgnames[] =
+    {
+      "option-argv0",
+      "lt-option-argv0",
+#ifdef G_OS_WIN32
+      "option-argv0.exe",
+#endif
+      NULL,
+    };
   gboolean retval;
+  gboolean fatal_errors = TRUE;
+
+  /* This test must pass on platforms where platform_get_argv0()
+   * is implemented. At the moment that means Linux/Cygwin,
+   * (which uses /proc/self/cmdline) or OpenBSD (which uses
+   * sysctl and KERN_PROC_ARGS). On other platforms the test
+   * is not expected to pass, but we'd still want to know
+   * how it does (the test code itself doesn't use any platform-specific
+   * functionality, the difference is internal to glib, so it's quite
+   * possible to run this test everywhere - it just won't pass on some
+   * platforms). Make errors non-fatal on these other plaforms,
+   * to prevent them from crashing hard on failed assertions,
+   * and make them call g_test_skip() instead.
+   */
+#if !defined HAVE_PROC_SELF_CMDLINE && !defined __OpenBSD__
+  fatal_errors = FALSE;
+#endif
 
   context = g_option_context_new (NULL);
   g_option_context_add_main_entries (context, entries, NULL);
   
   retval = g_option_context_parse (context, NULL, NULL, NULL);
-  g_assert (retval == TRUE);
-  g_assert (strcmp (g_get_prgname(), "option-argv0") == 0
-           || strcmp (g_get_prgname (), "lt-option-argv0") == 0);
+  if (fatal_errors)
+    {
+      g_assert_true (retval);
+      g_assert_true (g_strv_contains (expected_prgnames, g_get_prgname ()));
+    }
+  else
+    {
+      gboolean failed = FALSE;
+
+      if (!retval)
+        {
+          g_print ("g_option_context_parse() failed\n");
+          failed = TRUE;
+        }
+      else if (!g_strv_contains (expected_prgnames, g_get_prgname ()))
+        {
+          g_print ("program name `%s' is neither `option-argv0', nor `lt-option-argv0'\n", g_get_prgname());
+          failed = TRUE;
+        }
+      else
+        g_print ("The test unexpectedly passed\n");
+      if (failed)
+        g_test_skip ("platform_get_argv0() is not implemented [correctly?] on this platform");
+    }
 
   g_option_context_free (context);
 }
-#endif
 
 int
 main (int   argc,
@@ -56,9 +102,7 @@ main (int   argc,
 {
   g_test_init (&argc, &argv, "no_g_set_prgname", NULL);
 
-#if defined __linux || defined __OpenBSD__
   g_test_add_func ("/option/argv0", test_platform_argv0);
-#endif
 
   return g_test_run ();
 }
diff --git a/meson.build b/meson.build
index 09472deee..27cb9c03e 100644
--- a/meson.build
+++ b/meson.build
@@ -1898,6 +1898,53 @@ if cc.has_function('strlcpy')
   endif
 endif
 
+cmdline_test_code = '''
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#undef NDEBUG
+#include <assert.h>
+
+static int
+__getcmdline (void)
+{
+/* This code is a dumbed-down version of g_file_get_contents() */
+#define BUFSIZE 1024
+  char result[BUFSIZE];
+  struct stat stat_buf;
+
+  int fd = open ("/proc/self/cmdline", O_RDONLY|O_BINARY);
+  assert (fd >= 0);
+  assert (fstat (fd, &stat_buf) == 0);
+
+  if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode))
+    assert (read (fd, result, BUFSIZE) > 0);
+  else
+    {
+      FILE *f = fdopen (fd, "r");
+      assert (f != NULL);
+      assert (fread (result, 1, BUFSIZE, f) > 0);
+    }
+
+  return 0;
+}
+
+int
+main (void)
+{
+  exit (__getcmdline ());
+}'''
+
+if cc_can_run
+  rres = cc.run(cmdline_test_code, name : '/proc/self/cmdline')
+  have_proc_self_cmdline = rres.compiled() and rres.returncode() == 0
+else
+  have_proc_self_cmdline = meson.get_cross_property('have_proc_self_cmdline', false)
+endif
+
+glib_conf.set('HAVE_PROC_SELF_CMDLINE', have_proc_self_cmdline)
+
 python = import('python').find_installation('python3')
 # used for '#!/usr/bin/env <name>'
 python_name = 'python3'


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]