[glib] goption: [linux] Look in /proc/self/cmdline for argv0 if not specified



commit 14bb138d581b40bbd850c85ae63c8391a1671696
Author: Colin Walters <walters verbum org>
Date:   Fri Mar 25 11:59:33 2011 -0400

    goption: [linux] Look in /proc/self/cmdline for argv0 if not specified
    
    We really shouldn't use <unknown> 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(-)
---
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 ("<unknown>");
+	g_set_prgname ("<unknown>");
+
+      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 <walters verbum org>
+ */
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+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, "<unknown>") == 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);
 



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