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.
This commit is contained in:
Руслан Ижбулатов 2019-03-20 21:19:29 +00:00
parent cf54fc3600
commit 4c038a27ff
3 changed files with 99 additions and 8 deletions

View File

@ -1815,7 +1815,7 @@ free_pending_nulls (GOptionContext *context,
static char * static char *
platform_get_argv0 (void) platform_get_argv0 (void)
{ {
#if defined __linux #ifdef HAVE_PROC_SELF_CMDLINE
char *cmdline; char *cmdline;
char *base_arg0; char *base_arg0;
gsize len; gsize len;

View File

@ -21,13 +21,13 @@
* Authors: Colin Walters <walters@verbum.org> * Authors: Colin Walters <walters@verbum.org>
*/ */
#include "config.h"
#include <glib.h> #include <glib.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#if defined __linux || defined __OpenBSD__
static void static void
test_platform_argv0 (void) test_platform_argv0 (void)
{ {
@ -36,19 +36,65 @@ test_platform_argv0 (void)
GOptionEntry entries [] = GOptionEntry entries [] =
{ { "test", 't', 0, G_OPTION_ARG_STRING, &arg, NULL, NULL }, { { "test", 't', 0, G_OPTION_ARG_STRING, &arg, NULL, 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 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); context = g_option_context_new (NULL);
g_option_context_add_main_entries (context, entries, NULL); g_option_context_add_main_entries (context, entries, NULL);
retval = g_option_context_parse (context, NULL, NULL, NULL); retval = g_option_context_parse (context, NULL, NULL, NULL);
g_assert (retval == TRUE); if (fatal_errors)
g_assert (strcmp (g_get_prgname(), "option-argv0") == 0 {
|| strcmp (g_get_prgname (), "lt-option-argv0") == 0); 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); g_option_context_free (context);
} }
#endif
int int
main (int argc, main (int argc,
@ -56,9 +102,7 @@ main (int argc,
{ {
g_test_init (&argc, &argv, "no_g_set_prgname", NULL); g_test_init (&argc, &argv, "no_g_set_prgname", NULL);
#if defined __linux || defined __OpenBSD__
g_test_add_func ("/option/argv0", test_platform_argv0); g_test_add_func ("/option/argv0", test_platform_argv0);
#endif
return g_test_run (); return g_test_run ();
} }

View File

@ -1898,6 +1898,53 @@ if cc.has_function('strlcpy')
endif endif
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') python = import('python').find_installation('python3')
# used for '#!/usr/bin/env <name>' # used for '#!/usr/bin/env <name>'
python_name = 'python3' python_name = 'python3'