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 */ +#include "config.h" #include #include #include #include -#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 +#include +#include +#include +#undef NDEBUG +#include + +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 ' python_name = 'python3'