From 14bb138d581b40bbd850c85ae63c8391a1671696 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 25 Mar 2011 11:59:33 -0400 Subject: [PATCH] goption: [linux] Look in /proc/self/cmdline for argv0 if not specified We really shouldn't use when we can perfectly easily get argv0 out of /proc. This avoids people having to pass argv down into gtk_init/g_option_context_parse etc., which is important because GTK+ uses it to initialize the WM_CLASS, which in turn GNOME Shell consumes for application tracking. https://bugzilla.gnome.org/show_bug.cgi?id=644309 --- glib/goption.c | 50 ++++++++++++++++++++++++++++++----- glib/tests/Makefile.am | 4 +++ glib/tests/option-argv0.c | 63 +++++++++++++++++++++++++++++++++++++++++++++ glib/tests/option-context.c | 25 +++--------------- 4 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 glib/tests/option-argv0.c diff --git a/glib/goption.c b/glib/goption.c index 9a7adab..0e0437c 100644 --- a/glib/goption.c +++ b/glib/goption.c @@ -1657,6 +1657,39 @@ free_pending_nulls (GOptionContext *context, context->pending_nulls = NULL; } +/* Use a platform-specific mechanism to look up the first argument to + * the current process. + * Note if you implement this for other platforms, also add it to + * tests/option-argv0.c + */ +static char * +platform_get_argv0 (void) +{ +#ifdef __linux + char *cmdline; + char *base_arg0; + gsize len; + + if (!g_file_get_contents ("/proc/self/cmdline", + &cmdline, + &len, + NULL)) + return NULL; + /* Sanity check for a NUL terminator. */ + if (!memchr (cmdline, 0, len)) + return NULL; + /* We could just return cmdline, but I think it's better + * to hold on to a smaller malloc block; the arguments + * could be large. + */ + base_arg0 = g_path_get_basename (cmdline); + g_free (cmdline); + return base_arg0; +#endif + + return NULL; +} + /** * g_option_context_parse: * @context: a #GOptionContext @@ -1704,16 +1737,19 @@ g_option_context_parse (GOptionContext *context, /* Set program name */ if (!g_get_prgname()) { + gchar *prgname; + if (argc && argv && *argc) - { - gchar *prgname; + prgname = g_path_get_basename ((*argv)[0]); + else + prgname = platform_get_argv0 (); - prgname = g_path_get_basename ((*argv)[0]); - g_set_prgname (prgname); - g_free (prgname); - } + if (prgname) + g_set_prgname (prgname); else - g_set_prgname (""); + g_set_prgname (""); + + g_free (prgname); } /* Call pre-parse hooks */ diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am index f2dfa49..ea7da1f 100644 --- a/glib/tests/Makefile.am +++ b/glib/tests/Makefile.am @@ -17,6 +17,10 @@ TEST_PROGS += option-context option_context_SOURCES = option-context.c option_context_LDADD = $(progs_ldadd) +TEST_PROGS += option-argv0 +option_argv0_SOURCES = option-argv0.c +option_argv0_LDADD = $(progs_ldadd) + TEST_PROGS += keyfile keyfile_SOURCES = keyfile.c keyfile_LDADD = $(progs_ldadd) diff --git a/glib/tests/option-argv0.c b/glib/tests/option-argv0.c new file mode 100644 index 0000000..182521e --- /dev/null +++ b/glib/tests/option-argv0.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This work is provided "as is"; redistribution and modification + * in whole or in part, in any medium, physical or electronic is + * permitted without restriction. + * + * This work is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In no event shall the authors or contributors be liable for any + * direct, indirect, incidental, special, exemplary, or consequential + * damages (including, but not limited to, procurement of substitute + * goods or services; loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, whether + * in contract, strict liability, or tort (including negligence or + * otherwise) arising in any way out of the use of this software, even + * if advised of the possibility of such damage. + * + * Authors: Colin Walters + */ + +#include + +#include +#include +#include + +static void +test_platform_argv0 (void) +{ + GOptionContext *context; + gboolean arg; + GOptionEntry entries [] = + { { "test", 't', 0, G_OPTION_ARG_STRING, &arg, NULL, NULL }, + { NULL } }; + gboolean retval; + + 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); +} + +int +main (int argc, + char *argv[]) +{ + /* Note - we can't actually use g_test_* because g_test_init mutates + * g_get_prgname() which is exactly what we wanted to test =/ + */ +#ifdef __linux + g_print ("/option/argv0: "); + test_platform_argv0 (); + g_print ("OK\n"); +#endif + + return 0; +} diff --git a/glib/tests/option-context.c b/glib/tests/option-context.c index 163c3a4..bf24ec3 100644 --- a/glib/tests/option-context.c +++ b/glib/tests/option-context.c @@ -1308,27 +1308,6 @@ add_test1 (void) } void -empty_test1 (void) -{ - GOptionContext *context; - GOptionEntry entries [] = - { { NULL } }; - char *prgname; - - g_set_prgname (NULL); - context = g_option_context_new (NULL); - - g_option_context_add_main_entries (context, entries, NULL); - - g_option_context_parse (context, NULL, NULL, NULL); - - prgname = g_get_prgname (); - g_assert (prgname && strcmp (prgname, "") == 0); - - g_option_context_free (context); -} - -void empty_test2 (void) { GOptionContext *context; @@ -2031,7 +2010,9 @@ main (int argc, g_test_add_func ("/option/context/add", add_test1); /* Test parsing empty args */ - g_test_add_func ("/option/context/empty1", empty_test1); + /* Note there used to be an empty1 here, but it effectively moved + * to option-argv0.c. + */ g_test_add_func ("/option/context/empty2", empty_test2); g_test_add_func ("/option/context/empty3", empty_test3); -- 2.7.4