[patch] Auto session bus launch from libdbus, take 2

Havoc Pennington hp at redhat.com
Sat Sep 16 16:06:23 PDT 2006


Hi,

Here is a patch to add a guaranteed machine uuid on any system that has 
libdbus installed.

The only large problem with this dbus-uuidgen is that it uses the static 
version of libdbus that has the private string, random bytes, etc. 
utility functions exported, so the executable is a couple hundred K for 
no good reason.

Not committing this yet since I'm not sure how it interacts with 1.0, 
plus it could use some review.

Unrelated, I realized that on an embedded system someone could make 
dbus-daemon use the shared libdbus by removing the 
private-symbol-stripping - that would give 100K or so of disk savings.
Just in case any list lurkers could use that space ;-)

Havoc

-------------- next part --------------
Index: ChangeLog
===================================================================
RCS file: /cvs/dbus/dbus/ChangeLog,v
retrieving revision 1.1127
diff -u -p -r1.1127 ChangeLog
--- ChangeLog	16 Sep 2006 19:24:07 -0000	1.1127
+++ ChangeLog	16 Sep 2006 22:59:46 -0000
@@ -1,5 +1,11 @@
 2006-09-16  Havoc Pennington  <hp at redhat.com>
 
+	* tools/dbus-uuidgen.c: add a machine uuid generator command,
+	which can go in postinstall scripts and ensure we have a unique
+	machine id on any system running dbus.
+
+2006-09-16  Havoc Pennington  <hp at redhat.com>
+
 	* dbus/dbus-transport.c (_dbus_transport_open): modify to delegate
 	to _dbus_transport_open_platform_specific,
 	_dbus_transport_open_socket,
Index: tools/Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/tools/Makefile.am,v
retrieving revision 1.20
diff -u -p -r1.20 Makefile.am
--- tools/Makefile.am	8 Aug 2006 21:30:31 -0000	1.20
+++ tools/Makefile.am	16 Sep 2006 22:59:47 -0000
@@ -1,6 +1,6 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\"
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\" -DDBUS_CONFIG_DIR=\""$(sysconfdir)/dbus-1"\"
 
-bin_PROGRAMS=dbus-send dbus-monitor dbus-launch dbus-cleanup-sockets
+bin_PROGRAMS=dbus-send dbus-monitor dbus-launch dbus-cleanup-sockets dbus-uuidgen
 
 dbus_send_SOURCES=				\
 	dbus-print-message.c			\
@@ -18,11 +18,15 @@ dbus_launch_SOURCES=				\
 dbus_cleanup_sockets_SOURCES=			\
 	dbus-cleanup-sockets.c
 
+dbus_uuidgen_SOURCES=				\
+	dbus-uuidgen.c
+
 dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la
 dbus_monitor_LDADD= $(top_builddir)/dbus/libdbus-1.la
+dbus_uuidgen_LDADD= $(top_builddir)/dbus/libdbus-convenience.la
 dbus_launch_LDADD= $(DBUS_X_LIBS)
 
-man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1
+man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 dbus-uuidgen.1
 EXTRA_DIST = $(man_MANS) run-with-tmp-session-bus.sh
 CLEANFILES = 				\
 	run-with-tmp-session-bus.conf
Index: tools/dbus-cleanup-sockets.1
===================================================================
RCS file: /cvs/dbus/dbus/tools/dbus-cleanup-sockets.1,v
retrieving revision 1.2
diff -u -p -r1.2 dbus-cleanup-sockets.1
--- tools/dbus-cleanup-sockets.1	3 Aug 2006 20:34:36 -0000	1.2
+++ tools/dbus-cleanup-sockets.1	16 Sep 2006 22:59:47 -0000
@@ -11,8 +11,8 @@ dbus-cleanup-sockets \- clean up leftove
 
 .SH DESCRIPTION
 
-The \fIdbus-cleanup-sockets\fP command cleans up sockets used for
-D-Bus connections. See http://www.freedesktop.org/software/dbus/ for
+The \fIdbus-cleanup-sockets\fP command cleans up unused D-Bus
+connection sockets. See http://www.freedesktop.org/software/dbus/ for
 more information about the big picture.
 
 .PP
@@ -21,6 +21,19 @@ in the standard default socket directory
 per-user-login-session message bus; this is usually /tmp. 
 Optionally, you can pass a different directory on the command line.
 
+.PP
+On Linux, this program is essentially useless, because D-Bus defaults
+to using "abstract sockets" that exist only in memory and don't have a
+corresponding file in /tmp. 
+
+.PP
+On most other flavors of UNIX, it's possible for the socket files to
+leak when programs using D-Bus exit abnormally or without closing
+their D-Bus connections. Thus, it might be interesting to run
+dbus-cleanup-sockets in a cron job to mop up any leaked sockets.
+Or you can just ignore the leaked sockets, they aren't really hurting
+anything, other than cluttering the output of "ls /tmp"
+
 .SH AUTHOR
 dbus-cleanup-sockets was adapted by Havoc Pennington from
 linc-cleanup-sockets written by Michael Meeks.
Index: tools/dbus-uuidgen.1
===================================================================
RCS file: tools/dbus-uuidgen.1
diff -N tools/dbus-uuidgen.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/dbus-uuidgen.1	16 Sep 2006 22:59:47 -0000
@@ -0,0 +1,62 @@
+.\" 
+.\" dbus-uuidgen manual page.
+.\" Copyright (C) 2006 Red Hat, Inc.
+.\"
+.TH dbus-uuidgen 1
+.SH NAME
+dbus-uuidgen \- Utility to generate UUIDs
+.SH SYNOPSIS
+.PP
+.B dbus-uuidgen [\-\-version] [\-\-ensure[=FILENAME]] [\-\-get[=FILENAME]]
+
+.SH DESCRIPTION
+
+The \fIdbus-uuidgen\fP command generates a universally unique ID. It
+is similar to the "uuidgen" command found on many systems already, but 
+D-Bus can't rely on that command existing everywhere.
+
+.PP
+See http://www.freedesktop.org/software/dbus/ for more information
+about D-Bus.
+
+.PP
+The primary usage of \fIdbus-uuidgen\fP is to run in the post-install
+script of a D-Bus package with the "--ensure" option. This 
+will ensure that /etc/dbus-1/machine-id (or
+a specified file) exists and has the uuid in it.
+It won't overwrite an existing uuid, since this id should remain fixed
+for a single machine.
+
+.PP
+If you run the command with no options it just prints a new uuid.
+
+.PP
+If you run it with --get, it prints the machine uuid by default, or
+the uuid in the specified file if you specify a file.
+
+.SH OPTIONS
+The following options are supported:
+.TP
+.I "--get[=FILENAME]"
+If a filename is not given, defaults to sysconfdir/dbus-1/machine-id
+(sysconfdir is usually /etc). If this file exists and is valid, the
+uuid in the file is printed on stdout. Otherwise, the command exits 
+with a nonzero status.
+
+.TP
+.I "--ensure[=FILENAME]"
+If a filename is not given, defaults to sysconfdir/dbus-1/machine-id
+(sysconfdir is usually /etc). If this file exists then it will be
+validated, and a failure code returned if it contains the wrong thing.
+If the file does not exist, it will be created with a new uuid in it.
+
+.TP
+.I "--version"
+Print the version of dbus-uuidgen
+
+.SH AUTHOR
+See http://www.freedesktop.org/software/dbus/doc/AUTHORS
+
+.SH BUGS
+Please send bug reports to the D-Bus mailing list or bug tracker,
+see http://www.freedesktop.org/software/dbus/
Index: tools/dbus-uuidgen.c
===================================================================
RCS file: tools/dbus-uuidgen.c
diff -N tools/dbus-uuidgen.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/dbus-uuidgen.c	16 Sep 2006 22:59:47 -0000
@@ -0,0 +1,269 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-uuidgen.c  Utility program to create UUIDs
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dbus/dbus-sysdeps.h>
+#include <dbus/dbus-string.h>
+
+static void
+delete_leading_whitespace (DBusString *str)
+{
+  int i;
+  
+  _dbus_string_skip_white (str, 0, &i);
+
+  if (i > 0)
+    _dbus_string_delete (str, 0, i);
+}
+
+static void
+usage (char *name, int ecode)
+{
+  if (name == NULL)
+    name = "dbus-uuidgen";
+  
+  fprintf (stderr, "Usage: %s [--ensure[=FILENAME]] [--get[=FILENAME]]\n", name);
+  exit (ecode);
+}
+
+static void
+version (void)
+{
+  printf ("D-Bus UUID Generator %s\n"
+          "Copyright (C) 2006 Red Hat, Inc.\n"
+          "This is free software; see the source for copying conditions.\n"
+          "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
+          VERSION);
+  exit (0);
+}
+
+/* should not modify str if it returns false */
+static dbus_bool_t
+get_arg(const char *arg,
+        const char *option,
+        DBusString *str)
+{
+  const char *fn;
+
+  if (strlen(arg) < strlen(option))
+    return FALSE;
+  
+  fn = arg + strlen(option);
+
+  if (!(*fn == '=' || *fn == ' ' || *fn == '\0'))
+    {
+      usage (NULL, 1);
+    }
+  
+  if (*fn == '=')
+    ++fn;
+  
+  while (*fn == ' ' && *fn != '\0')
+    ++fn;
+  
+  if (*fn != '\0')
+    {
+      _dbus_string_init_const (str, fn);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+  DBusString filename;
+  DBusString contents;
+  dbus_bool_t ensure_uuid;
+  dbus_bool_t get_uuid;
+
+  ensure_uuid = FALSE;
+  get_uuid = FALSE;
+  
+  _dbus_string_init_const (&filename, DBUS_CONFIG_DIR "/machine-id");
+
+  for (i = 1; i < argc; i++)
+    {
+      char *arg = argv[i];
+
+      if (strncmp (arg, "--ensure", strlen("--ensure")) == 0)
+        {
+          get_arg (arg, "--ensure", &filename);
+          ensure_uuid = TRUE;
+        }
+      else if (strncmp (arg, "--get", strlen("--get")) == 0)
+        {
+          get_arg (arg, "--get", &filename);
+          get_uuid = TRUE;
+        }
+      else if (strcmp (arg, "--help") == 0)
+	usage (argv[0], 0);
+      else if (strcmp (arg, "--version") == 0)
+        version ();
+      else
+        usage (argv[0], 1);
+    }
+
+  if (get_uuid && ensure_uuid)
+    {
+      fprintf (stderr, "Can't specify both --get-for-machine and --ensure-for-machine\n");
+      exit (1);
+    }
+  
+  /* Don't cut-and-paste this string code as an example, none of it
+   * checks for out of memory or frees anything.
+   */
+  
+  _dbus_string_init (&contents);
+  if ((get_uuid || ensure_uuid) && _dbus_file_get_contents (&contents, &filename, NULL))
+    {
+
+      /* If the file exists and is valid we exit successfully;
+       * if it exists but contains junk, we don't overwrite
+       * it (don't want to lose data) but we also exit with
+       * a failure code.
+       */
+      
+      DBusString decoded;
+      int end;
+      
+      delete_leading_whitespace (&contents);
+      _dbus_string_init (&decoded);
+
+      /* this function will allow the last hex pair to be just one
+       * character instead of 2, so it isn't 100% as strict as
+       * it should be for this.
+       */
+      _dbus_string_hex_decode (&contents, 0, &end, &decoded, 0);
+
+      if (end == 0)
+        {
+          fprintf (stderr, "File '%s' contains something other than a valid hex-encoded uuid\n",
+                   _dbus_string_get_const_data (&filename));
+          exit (1);
+        }
+      
+      _dbus_string_delete (&contents, 0, end);
+      delete_leading_whitespace (&contents);
+      
+      if (_dbus_string_get_length (&contents) > 0)
+        {
+          fprintf (stderr, "File '%s' contains trailing stuff that is not a valid hex-encoded uuid: '%s'\n",
+                   _dbus_string_get_const_data (&filename),
+                   _dbus_string_get_const_data (&contents));
+          exit (1);
+        }
+
+      if (_dbus_string_get_length (&decoded) != 16)
+        {
+          fprintf (stderr, "File '%s' contains %d hex-encoded bytes instead of 16\n",
+                   _dbus_string_get_const_data (&filename),
+                   _dbus_string_get_length (&decoded));
+          exit (1);
+        }
+
+      if (get_uuid)
+        {
+          DBusString encoded;
+          _dbus_string_init (&encoded);
+          _dbus_string_hex_encode (&decoded, 0, &encoded, 0);
+          
+          printf ("%s\n", _dbus_string_get_const_data (&encoded));
+        }
+      
+      /* don't bother to free all the strings */
+      
+      exit (0);
+    }
+  else if (get_uuid)
+    {
+      fprintf (stderr, "No valid uuid in file '%s'\n",
+               _dbus_string_get_const_data (&filename));
+      exit (1);
+    }
+  else
+    {
+      DBusString bytes;
+      DBusString encoded;
+      DBusError error;
+      long tv_sec;
+      union {
+        dbus_uint32_t number;
+        unsigned char bytes[4];
+      } val32;
+      
+      _dbus_string_init (&bytes);
+      _dbus_get_current_time (&tv_sec, NULL);
+      val32.number = tv_sec;
+  
+      _dbus_string_append_4_aligned (&bytes, val32.bytes);
+  
+      if (!_dbus_generate_random_bytes (&bytes, 12))
+        {
+          fprintf (stderr, "Failed to generate random bytes for uuid");
+          exit (1);
+        }
+
+      _dbus_string_init (&encoded);
+
+      _dbus_string_hex_encode (&bytes, 0, &encoded, 0);
+
+      if (ensure_uuid)
+        {
+          /* FIXME this is racy; we need a save_file_exclusively
+           * function. But in practice this should be fine.
+           *
+           * - first be sure we can create the file and it
+           *   doesn't exist by creating it empty with O_EXCL
+           * - then create it by creating a temporary file and
+           *   overwriting atomically with rename()
+           */
+          dbus_error_init (&error);
+          if (!_dbus_create_file_exclusively (&filename, &error))
+            {
+              fprintf (stderr, "Could not create uuid file '%s': %s\n",
+                       _dbus_string_get_const_data (&filename),
+                       error.message);
+              exit (1);
+            }
+
+          if (!_dbus_string_save_to_file (&encoded, &filename, &error))
+            {
+              fprintf (stderr, "Failed to save new uuid to '%s': %s\n",
+                       _dbus_string_get_const_data (&filename),
+                       error.message);
+              exit (1);
+            }
+        }
+      else
+        {
+          printf ("%s\n",
+                  _dbus_string_get_const_data (&encoded));
+        }
+      
+      exit (0);
+    }
+}


More information about the dbus mailing list