コード例 #1
0
ファイル: dbus-transport.c プロジェクト: zsx/windbus
/**
 * Creates a new transport for the "autostart" method.
 * This creates a client-side of a transport.
 *
 * @param error address where an error can be returned.
 * @returns a new transport, or #NULL on failure.
 */
static DBusTransport*
_dbus_transport_new_for_autolaunch (DBusError      *error)
{
  DBusString address;
  DBusTransport *result = NULL;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  if (!_dbus_get_autolaunch_address (&address, error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      goto out;
    }

  result = check_address (_dbus_string_get_const_data (&address), error);
  if (result == NULL)
    _DBUS_ASSERT_ERROR_IS_SET (error);
  else
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

 out:
  _dbus_string_free (&address);
  return result;
}
コード例 #2
0
ファイル: dbus-bus.c プロジェクト: jameshilliard/WECB-BH-GPL
/**
 * Starts a service that will request ownership of the given name.
 * The returned result will be one of be one of
 * #DBUS_START_REPLY_SUCCESS or #DBUS_START_REPLY_ALREADY_RUNNING if
 * successful.  Pass #NULL if you don't care about the result.
 * 
 * The flags parameter is for future expansion, currently you should
 * specify 0.
 *
 * @param connection the connection
 * @param name the name we want the new service to request
 * @param flags the flags (should always be 0 for now)
 * @param result a place to store the result or #NULL
 * @param error location to store any errors
 * @returns #TRUE if the activation succeeded, #FALSE if not
 */
dbus_bool_t
dbus_bus_start_service_by_name (DBusConnection *connection,
                                const char     *name,
                                dbus_uint32_t   flags,
                                dbus_uint32_t  *result,
                                DBusError      *error)
{
  DBusMessage *msg;
  DBusMessage *reply;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE);
  
  msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                      DBUS_PATH_DBUS,
                                      DBUS_INTERFACE_DBUS,
                                      "StartServiceByName");

  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name,
			  	 DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID))
    {
      dbus_message_unref (msg);
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  reply = dbus_connection_send_with_reply_and_block (connection, msg,
                                                     -1, error);
  dbus_message_unref (msg);

  if (reply == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return FALSE;
    }

  if (dbus_set_error_from_message (error, reply))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return FALSE;
    }

  if (result != NULL &&
      !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
	      		      result, DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return FALSE;
    }
  
  dbus_message_unref (reply);
  return TRUE;
}
コード例 #3
0
ファイル: dbus-bus.c プロジェクト: jameshilliard/WECB-BH-GPL
/**
 * Checks whether a certain name has an owner.
 *
 * @param connection the connection
 * @param name the name
 * @param error location to store any errors
 * @returns #TRUE if the name exists, #FALSE if not or on error
 */
dbus_bool_t
dbus_bus_name_has_owner (DBusConnection *connection,
			 const char     *name,
                         DBusError      *error)
{
  DBusMessage *message, *reply;
  dbus_bool_t exists;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_fail (name != NULL, FALSE);
  _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE);
  _dbus_return_val_if_error_is_set (error, FALSE);
  
  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                          DBUS_PATH_DBUS,
                                          DBUS_INTERFACE_DBUS,
                                          "NameHasOwner");
  if (message == NULL)
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!dbus_message_append_args (message,
				 DBUS_TYPE_STRING, &name,
				 DBUS_TYPE_INVALID))
    {
      dbus_message_unref (message);
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
  dbus_message_unref (message);

  if (reply == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return FALSE;
    }

  if (!dbus_message_get_args (reply, error,
                              DBUS_TYPE_BOOLEAN, &exists,
                              DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return FALSE;
    }
  
  dbus_message_unref (reply);
  return exists;
}
コード例 #4
0
ファイル: activation-helper.c プロジェクト: mirsal/dbus
static dbus_bool_t
get_parameters_for_service (BusDesktopFile *desktop_file,
                            const char     *service_name,
                            char          **exec,
                            char          **user,
                            DBusError      *error)
{
    char *exec_tmp;
    char *user_tmp;

    exec_tmp = NULL;
    user_tmp = NULL;

    /* check the name of the service */
    if (!check_service_name (desktop_file, service_name, error))
        goto failed;

    /* get the complete path of the executable */
    if (!bus_desktop_file_get_string (desktop_file,
                                      DBUS_SERVICE_SECTION,
                                      DBUS_SERVICE_EXEC,
                                      &exec_tmp,
                                      error))
    {
        _DBUS_ASSERT_ERROR_IS_SET (error);
        goto failed;
    }

    /* get the user that should run this service - user is compulsary for system activation */
    if (!bus_desktop_file_get_string (desktop_file,
                                      DBUS_SERVICE_SECTION,
                                      DBUS_SERVICE_USER,
                                      &user_tmp,
                                      error))
    {
        _DBUS_ASSERT_ERROR_IS_SET (error);
        goto failed;
    }

    /* only assign if all the checks passed */
    *exec = exec_tmp;
    *user = user_tmp;
    return TRUE;

failed:
    dbus_free (exec_tmp);
    dbus_free (user_tmp);
    return FALSE;
}
コード例 #5
0
ファイル: driver.c プロジェクト: jameshilliard/WECB-BH-GPL
static dbus_bool_t
bus_driver_handle_reload_config (DBusConnection *connection,
				 BusTransaction *transaction,
				 DBusMessage    *message,
				 DBusError      *error)
{
  BusContext *context;
  dbus_bool_t retval;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  retval = FALSE;

  context = bus_connection_get_context (connection);
  if (!bus_context_reload_config (context, error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      goto out;
    }

  retval = TRUE;
  
 out:
  return retval;
}
コード例 #6
0
ファイル: main.c プロジェクト: psunkari/spicebird
static dbus_bool_t
handle_reload_watch (DBusWatch    *watch,
		     unsigned int  flags,
		     void         *data)
{
  DBusError error;
  DBusString str;
  _dbus_string_init (&str);
  if ((reload_pipe[RELOAD_READ_END] > 0) &&
      _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
    {
      _dbus_warn ("Couldn't read from reload pipe.\n");
      close_reload_pipe ();
      return TRUE;
    }
  _dbus_string_free (&str);

  /* this can only fail if we don't understand the config file
   * or OOM.  Either way we should just stick with the currently
   * loaded config.
   */
  dbus_error_init (&error);
  if (! bus_context_reload_config (context, &error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (&error);
      _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
		    dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
      _dbus_warn ("Unable to reload configuration: %s\n",
		  error.message);
      dbus_error_free (&error);
    }
  return TRUE;
}
コード例 #7
0
ファイル: test-launch-helper.c プロジェクト: halfline/dbus
/* returns true if good things happen, or if we get OOM */
static dbus_bool_t
bus_activation_helper_oom_test (void        *data,
                                dbus_bool_t  have_memory)
{
  const char *service;
  DBusError error;
  dbus_bool_t retval;

  service = (const char *) data;
  retval = TRUE;

  dbus_error_init (&error);

  if (!run_launch_helper (service, &error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (&error);
      /* we failed, but a OOM is good */
      if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
        {
          _dbus_warn ("FAILED SELF TEST: Error: %s", error.message);
          retval = FALSE;
        }
      dbus_error_free (&error);
    }
  else
    {
      /* we succeeded, yay! */
      _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
    }
  return retval;
}
コード例 #8
0
/**
 * For use by the dbus-uuidgen binary ONLY, do not call this.
 * We can and will change this function without modifying
 * the libdbus soname.
 *
 * @param filename the file or #NULL for the machine ID file
 * @param uuid_p out param to return the uuid
 * @param create_if_not_found whether to create it if not already there
 * @param error error return
 * @returns #FALSE if error is set
 */
dbus_bool_t
dbus_internal_do_not_use_get_uuid (const char *filename,
                                   char      **uuid_p,
                                   dbus_bool_t create_if_not_found,
                                   DBusError  *error)
{
  DBusGUID uuid;
  
  if (filename)
    {
      DBusString filename_str;
      _dbus_string_init_const (&filename_str, filename);
      if (!_dbus_read_uuid_file (&filename_str, &uuid, create_if_not_found, error))
        goto error;
    }
  else
    {
      if (!_dbus_read_local_machine_uuid (&uuid, create_if_not_found, error))
        goto error;
    }

  if (!return_uuid(&uuid, uuid_p, error))
    goto error;

  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  return FALSE;
}
コード例 #9
0
ファイル: dbus-bus.c プロジェクト: jameshilliard/WECB-BH-GPL
static void
send_no_return_values (DBusConnection *connection,
                       DBusMessage    *msg,
                       DBusError      *error)
{
  if (error)
    {
      /* Block to check success codepath */
      DBusMessage *reply;
      
      reply = dbus_connection_send_with_reply_and_block (connection, msg,
                                                         -1, error);
      
      if (reply == NULL)
        _DBUS_ASSERT_ERROR_IS_SET (error);
      else
        dbus_message_unref (reply);
    }
  else
    {
      /* Silently-fail nonblocking codepath */
      dbus_message_set_no_reply (msg, TRUE);
      dbus_connection_send (connection, msg, NULL);
    }
}
コード例 #10
0
ファイル: dbus-transport.c プロジェクト: zsx/windbus
static DBusTransportOpenResult
_dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
                                 DBusTransport    **transport_p,
                                 DBusError         *error)
{
  const char *method;
  
  method = dbus_address_entry_get_method (entry);
  _dbus_assert (method != NULL);

  if (strcmp (method, "autolaunch") == 0)
    {
      *transport_p = _dbus_transport_new_for_autolaunch (error);

      if (*transport_p == NULL)
        {
          _DBUS_ASSERT_ERROR_IS_SET (error);
          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
          return DBUS_TRANSPORT_OPEN_OK;
        }      
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
    }
}
コード例 #11
0
/**
 * Creates a new transport for the given Unix domain socket
 * path. This creates a client-side of a transport.
 *
 * @todo once we add a way to escape paths in a dbus
 * address, this function needs to do escaping.
 *
 * @param path the path to the domain socket.
 * @param abstract #TRUE to use abstract socket namespace
 * @param error address where an error can be returned.
 * @returns a new transport, or #NULL on failure.
 */
DBusTransport*
_dbus_transport_new_for_domain_socket (const char     *path,
                                       dbus_bool_t     abstract,
                                       DBusError      *error)
{
  int fd;
  DBusTransport *transport;
  DBusString address;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  fd = -1;

  if ((abstract &&
       !_dbus_string_append (&address, "unix:abstract=")) ||
      (!abstract &&
       !_dbus_string_append (&address, "unix:path=")) ||
      !_dbus_string_append (&address, path))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_0;
    }
  
  fd = _dbus_connect_unix_socket (path, abstract, error);
  if (fd < 0)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      goto failed_0;
    }

  _dbus_verbose ("Successfully connected to unix socket %s\n",
                 path);

  transport = _dbus_transport_new_for_socket (fd, NULL, &address);
  if (transport == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_1;
    }
  
  _dbus_string_free (&address);
  
  return transport;

 failed_1:
  _dbus_close_socket (fd, NULL);
 failed_0:
  _dbus_string_free (&address);
  return NULL;
}
コード例 #12
0
/**
 * Creates a new transport for the given VMWare Communication Interface
 * CID and port. This creates a client-side of a transport.
 *
 * @param cid the virtual machine context ID to connect to
 * @param port the port to connect to
 * @param error address where an error can be returned.
 * @returns a new transport, or #NULL on failure.
 */
static
DBusTransport*
_dbus_transport_new_for_vmci (const char *cid,
                              const char *port,
                              DBusError  *error)
{
  int fd;
  DBusTransport *transport;
  DBusString address;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  fd = -1;

  if (!_dbus_string_append (&address, "vmci:cid=") ||
      !_dbus_string_append(&address, cid) ||
      !_dbus_string_append(&address, "port=") ||
      !_dbus_string_append(&address, port)) {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_0;
  }

  fd = _dbus_connect_vmci (cid, port, error);
  if (fd < 0)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      goto failed_0;
    }

  _dbus_verbose ("Successfully connected to vmci stream socket %s:%s\n",
                 cid, port);

  transport = _dbus_transport_new_for_socket (fd, NULL, &address);
  if (transport == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_1;
    }

  _dbus_string_free (&address);

  return transport;

 failed_1:
  _dbus_close_socket (fd, NULL);
 failed_0:
  _dbus_string_free (&address);
  return NULL;
}
コード例 #13
0
ファイル: dbus-internals.c プロジェクト: psunkari/spicebird
static dbus_bool_t
_dbus_create_uuid_file_exclusively (const DBusString *filename,
                                    DBusGUID         *uuid,
                                    DBusError        *error)
{
  DBusString encoded;

  if (!_dbus_string_init (&encoded))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  _dbus_generate_uuid (uuid);
  
  if (!_dbus_uuid_encode (uuid, &encoded))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  /* FIXME this is racy; we need a save_file_exclusively
   * function. But in practice this should be fine for now.
   *
   * - 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()
   */
  if (!_dbus_create_file_exclusively (filename, error))
    goto error;

  if (!_dbus_string_append_byte (&encoded, '\n'))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  if (!_dbus_string_save_to_file (&encoded, filename, error))
    goto error;

  if (!_dbus_make_file_world_readable (filename, error))
    goto error;

  _dbus_string_free (&encoded);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&encoded);
  return FALSE;        
}
コード例 #14
0
static dbus_bool_t
bus_driver_handle_activate_service (DBusConnection *connection,
                                    BusTransaction *transaction,
                                    DBusMessage    *message,
                                    DBusError      *error)
{
  dbus_uint32_t flags;
  const char *name;
  dbus_bool_t retval;
  BusActivation *activation;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  activation = bus_connection_get_activation (connection);
  
  if (!dbus_message_get_args (message, error,
                              DBUS_TYPE_STRING, &name,
                              DBUS_TYPE_UINT32, &flags,
                              DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
      return FALSE;
    }

  retval = FALSE;

  if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
                                        message, name, error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _dbus_verbose ("bus_activation_activate_service() failed\n");
      goto out;
    }

  retval = TRUE;
  
 out:
  return retval;
}
コード例 #15
0
ファイル: test.c プロジェクト: 13824125580/hello-world
BusContext*
bus_context_new_test (const DBusString *test_data_dir,
                      const char       *filename)
{
  DBusError error;
  DBusString config_file;
  DBusString relative;
  BusContext *context;

  if (!_dbus_string_init (&config_file))
    {
      _dbus_warn ("No memory\n");
      return NULL;
    }

  if (!_dbus_string_copy (test_data_dir, 0,
                          &config_file, 0))
    {
      _dbus_warn ("No memory\n");
      _dbus_string_free (&config_file);
      return NULL;
    }

  _dbus_string_init_const (&relative, filename);

  if (!_dbus_concat_dir_and_file (&config_file, &relative))
    {
      _dbus_warn ("No memory\n");
      _dbus_string_free (&config_file);
      return NULL;
    }

  dbus_error_init (&error);
  context = bus_context_new (&config_file, BUS_CONTEXT_FLAG_NONE, NULL, NULL, NULL, &error);
  if (context == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (&error);

      _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n",
                  filename, error.message);

      dbus_error_free (&error);

      _dbus_string_free (&config_file);

      return NULL;
    }

  _dbus_string_free (&config_file);

  return context;
}
コード例 #16
0
static dbus_bool_t
bus_driver_handle_remove_match (DBusConnection *connection,
                                BusTransaction *transaction,
                                DBusMessage    *message,
                                DBusError      *error)
{
  BusMatchRule *rule;
  const char *text;
  DBusString str;
  BusMatchmaker *matchmaker;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  text = NULL;
  rule = NULL;
  
  if (!dbus_message_get_args (message, error,
                              DBUS_TYPE_STRING, &text,
                              DBUS_TYPE_INVALID))
    {
      _dbus_verbose ("No memory to get arguments to RemoveMatch\n");
      goto failed;
    }

  _dbus_string_init_const (&str, text);

  rule = bus_match_rule_parse (connection, &str, error);
  if (rule == NULL)
    goto failed;

  /* Send the ack before we remove the rule, since the ack is undone
   * on transaction cancel, but rule removal isn't.
   */
  if (!send_ack_reply (connection, transaction,
                       message, error))
    goto failed;
  
  matchmaker = bus_connection_get_matchmaker (connection);

  if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
    goto failed;

  bus_match_rule_unref (rule);
  
  return TRUE;

 failed:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  if (rule)
    bus_match_rule_unref (rule);
  return FALSE;
}
コード例 #17
0
static dbus_bool_t
do_load (const DBusString *full_path,
         Validity          validity,
         dbus_bool_t       oom_possible)
{
  BusConfigParser *parser;
  DBusError error;

  dbus_error_init (&error);

  parser = bus_config_load (full_path, TRUE, NULL, &error);
  if (parser == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (&error);

      if (oom_possible &&
          dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
        {
          _dbus_verbose ("Failed to load valid file due to OOM\n");
          dbus_error_free (&error);
          return TRUE;
        }
      else if (validity == VALID)
        {
          _dbus_warn ("Failed to load valid file but still had memory: %s\n",
                      error.message);

          dbus_error_free (&error);
          return FALSE;
        }
      else
        {
          dbus_error_free (&error);
          return TRUE;
        }
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (&error);

      bus_config_parser_unref (parser);

      if (validity == INVALID)
        {
          _dbus_warn ("Accepted invalid file\n");
          return FALSE;
        }

      return TRUE;
    }
}
コード例 #18
0
/**
 * Opens a TCP socket transport.
 * 
 * @param entry the address entry to try opening as a tcp transport.
 * @param transport_p return location for the opened transport
 * @param error error to be set
 * @returns result of the attempt
 */
DBusTransportOpenResult
_dbus_transport_open_socket(DBusAddressEntry  *entry,
                            DBusTransport    **transport_p,                            
                            DBusError         *error)
{
  const char *method;
  dbus_bool_t isTcp;
  dbus_bool_t isNonceTcp;
  
  method = dbus_address_entry_get_method (entry);
  _dbus_assert (method != NULL);

  isTcp = strcmp (method, "tcp") == 0;
  isNonceTcp = strcmp (method, "nonce-tcp") == 0;

  if (isTcp || isNonceTcp)
    {
      const char *host = dbus_address_entry_get_value (entry, "host");
      const char *port = dbus_address_entry_get_value (entry, "port");
      const char *family = dbus_address_entry_get_value (entry, "family");
      const char *noncefile = dbus_address_entry_get_value (entry, "noncefile");

      if ((isNonceTcp == TRUE) != (noncefile != NULL)) {
          _dbus_set_bad_address (error, method, "noncefile", NULL);
          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
      }

      if (port == NULL)
        {
          _dbus_set_bad_address (error, method, "port", NULL);
          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
        }

      *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, noncefile, error);
      if (*transport_p == NULL)
        {
          _DBUS_ASSERT_ERROR_IS_SET (error);
          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
          return DBUS_TRANSPORT_OPEN_OK;
        }
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
    }
}
コード例 #19
0
/**
 * Creates a VMCI stream socket connected to the given cid and port.
 * The connection fd is returned, and is set up as nonblocking.
 *
 * This will set FD_CLOEXEC for the socket returned.
 *
 * @param path the path to UNIX domain socket
 * @param abstract #TRUE to use abstract namespace
 * @param error return location for error code
 * @returns connection file descriptor or -1 on error
 */
static int
_dbus_connect_vmci (const char     *cid_str,
                    const char     *port_str,
                    DBusError      *error)
{
  int fd;
  size_t path_len;
  struct sockaddr_vm addr;
  unsigned int af_vmci, cid, port;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  _dbus_verbose ("connecting to VMCI stream socket %s:%s\n", cid_str, port_str);
  cid = atoi(cid_str);
  port = atoi(port_str);
  if ((af_vmci = VMCISock_GetAFValue()) < 0) {
    assert(0);
  }
  if (_dbus_open_socket(&fd, af_vmci, SOCK_STREAM, 0, error) < 0) {
    return fd;
  }
  _DBUS_ZERO (addr);
  addr.svm_family = af_vmci;
  addr.svm_cid = cid;
  addr.svm_port = port;
  if (connect (fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
    dbus_set_error (error,
        _dbus_error_from_errno (errno),
        "Failed to connect to VMCI (cid, port): %s:%s: %s",
        cid_str, port_str, _dbus_strerror (errno));

    _dbus_close (fd, NULL);
    fd = -1;

    return -1;
  }
  if (!_dbus_set_fd_nonblocking (fd, error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);

      _dbus_close (fd, NULL);
      fd = -1;

      return -1;
    }

  return fd;
}
コード例 #20
0
ファイル: dbus-nonce.c プロジェクト: halfline/dbus
/**
 * sends the nonce over a given socket. Blocks while doing so.
 *
 * @param fd the file descriptor to write the nonce data to (usually a socket)
 * @param noncefile the noncefile location to read the nonce from
 * @param error contains error details if FALSE is returned
 * @return TRUE iff the nonce was successfully sent. Note that this does not
 * indicate whether the server accepted the nonce.
 */
dbus_bool_t
_dbus_send_nonce (DBusSocket        fd,
                  const DBusString *noncefile,
                  DBusError        *error)
{
  dbus_bool_t read_result;
  int send_result;
  DBusString nonce;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (_dbus_string_get_length (noncefile) == 0)
    return FALSE;

  if (!_dbus_string_init (&nonce))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  read_result = _dbus_read_nonce (noncefile, &nonce, error);
  if (!read_result)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _dbus_string_free (&nonce);
      return FALSE;
    }
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce));

  _dbus_string_free (&nonce);

  if (send_result == -1)
    {
      dbus_set_error (error,
                      _dbus_error_from_system_errno (),
                      "Failed to send nonce (fd=%" DBUS_SOCKET_FORMAT "): %s",
                      _dbus_socket_printable (fd),
                      _dbus_strerror_from_errno ());
      return FALSE;
    }

  return TRUE;
}
コード例 #21
0
/**
 * Tries to interpret the address entry in a platform-specific
 * way, creating a platform-specific server type if appropriate.
 * Sets error if the result is not OK.
 * 
 * @param entry an address entry
 * @param server_p location to store a new DBusServer, or #NULL on failure.
 * @param error location to store rationale for failure on bad address
 * @returns the outcome
 * 
 */
DBusServerListenResult
_dbus_server_listen_platform_specific (DBusAddressEntry *entry,
                                       DBusServer      **server_p,
                                       DBusError        *error)
{
  const char *method;

  *server_p  = NULL;

  method = dbus_address_entry_get_method (entry);

  if (strcmp (method, "nonce-tcp") == 0)
    {
      const char *host;
      const char *port;
      const char *bind;
      const char *family;

      host = dbus_address_entry_get_value (entry, "host");
      bind = dbus_address_entry_get_value (entry, "bind");
      port = dbus_address_entry_get_value (entry, "port");
      family = dbus_address_entry_get_value (entry, "family");

      *server_p = _dbus_server_new_for_tcp_socket (host, bind, port,
                                                   family, error, TRUE);

      if (*server_p)
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR(error);
          return DBUS_SERVER_LISTEN_OK;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_SET(error);
          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }
    }
  else
    {
  _DBUS_ASSERT_ERROR_IS_CLEAR(error);
  return DBUS_SERVER_LISTEN_NOT_HANDLED;
}
}
コード例 #22
0
/**
 * Tries to interpret the address entry as a debug pipe entry.
 *
 * Sets error if the result is not OK.
 *
 * @param entry an address entry
 * @param server_p location to store a new DBusServer, or #NULL on failure.
 * @param error location to store rationale for failure on bad address
 * @returns the outcome
 *
 */
DBusServerListenResult
_dbus_server_listen_debug_pipe (DBusAddressEntry *entry,
                                DBusServer      **server_p,
                                DBusError        *error)
{
    const char *method;

    *server_p = NULL;

    method = dbus_address_entry_get_method (entry);

    if (strcmp (method, "debug-pipe") == 0)
    {
        const char *name = dbus_address_entry_get_value (entry, "name");

        if (name == NULL)
        {
            _dbus_set_bad_address(error, "debug-pipe", "name",
                                  NULL);
            return DBUS_SERVER_LISTEN_BAD_ADDRESS;
        }

        *server_p = _dbus_server_debug_pipe_new (name, error);

        if (*server_p)
        {
            _DBUS_ASSERT_ERROR_IS_CLEAR(error);
            return DBUS_SERVER_LISTEN_OK;
        }
        else
        {
            _DBUS_ASSERT_ERROR_IS_SET(error);
            return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }
    }
    else
    {
        _DBUS_ASSERT_ERROR_IS_CLEAR(error);
        return DBUS_SERVER_LISTEN_NOT_HANDLED;
    }
}
コード例 #23
0
/**
 * Opens a debug pipe transport, used in the test suite.
 *
 * @param entry the address entry to try opening as debug-pipe
 * @param transport_p return location for the opened transport
 * @param error error to be set
 * @returns result of the attempt
 */
DBusTransportOpenResult
_dbus_transport_open_debug_pipe (DBusAddressEntry  *entry,
                                 DBusTransport    **transport_p,
                                 DBusError         *error)
{
    const char *method;

    method = dbus_address_entry_get_method (entry);
    _dbus_assert (method != NULL);

    if (strcmp (method, "debug-pipe") == 0)
    {
        const char *name = dbus_address_entry_get_value (entry, "name");

        if (name == NULL)
        {
            _dbus_set_bad_address (error, "debug-pipe", "name",
                                   NULL);
            return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
        }

        *transport_p = _dbus_transport_debug_pipe_new (name, error);

        if (*transport_p == NULL)
        {
            _DBUS_ASSERT_ERROR_IS_SET (error);
            return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
        }
        else
        {
            _DBUS_ASSERT_ERROR_IS_CLEAR (error);
            return DBUS_TRANSPORT_OPEN_OK;
        }
    }
    else
    {
        _DBUS_ASSERT_ERROR_IS_CLEAR (error);
        return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
    }
}
コード例 #24
0
/**
 * Write the give UUID to a file.
 *
 * @param filename the file to write
 * @param uuid the UUID to save
 * @param error used to raise an error
 * @returns #FALSE on error
 */
dbus_bool_t
_dbus_write_uuid_file (const DBusString *filename,
                       const DBusGUID   *uuid,
                       DBusError        *error)
{
  DBusString encoded;

  if (!_dbus_string_init (&encoded))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!_dbus_uuid_encode (uuid, &encoded))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  if (!_dbus_string_append_byte (&encoded, '\n'))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
    goto error;

  _dbus_string_free (&encoded);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&encoded);
  return FALSE;        
}
コード例 #25
0
/**
 * Opens a VMCI stream socket transport.
 *
 * @param entry the address entry to try opening as a tcp transport.
 * @param transport_p return location for the opened transport
 * @param error error to be set
 * @returns result of the attempt
 */
DBusTransportOpenResult
_dbus_transport_open_vmci(DBusAddressEntry  *entry,
                            DBusTransport    **transport_p,
                            DBusError         *error)
{
  const char *method;
  const char *cid;
  const char *port;

  method = dbus_address_entry_get_method (entry);
  _dbus_assert (method != NULL);

  if (strcmp (method, "vmci") != 0) {
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
  }
  cid = dbus_address_entry_get_value (entry, "cid");
  port = dbus_address_entry_get_value (entry, "port");

  if (0 || port == NULL)
  {
    _dbus_set_bad_address (error, method, "port", NULL);
    return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
  }

  *transport_p = _dbus_transport_new_for_vmci (cid, port, error);
  if (*transport_p == NULL)
  {
    _DBUS_ASSERT_ERROR_IS_SET (error);
    return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
  }
  else
  {
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    return DBUS_TRANSPORT_OPEN_OK;
  }
}
コード例 #26
0
static dbus_bool_t
bus_driver_handle_reload_config (DBusConnection *connection,
				 BusTransaction *transaction,
				 DBusMessage    *message,
				 DBusError      *error)
{
  BusContext *context;
  DBusMessage *reply;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  reply = NULL;
  
  context = bus_connection_get_context (connection);
  if (!bus_context_reload_config (context, error))
    goto failed;

  reply = dbus_message_new_method_return (message);
  if (reply == NULL)
    goto oom;

  if (! bus_transaction_send_from_driver (transaction, connection, reply))
    goto oom;

  dbus_message_unref (reply);
  return TRUE;

 oom:
  BUS_SET_OOM (error);

 failed:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  if (reply)
    dbus_message_unref (reply);
  return FALSE;
}
コード例 #27
0
ファイル: main.c プロジェクト: AByzhynar/sdl_core
static dbus_bool_t
handle_reload_watch (DBusWatch    *watch,
		     unsigned int  flags,
		     void         *data)
{
  DBusError error;
  DBusString str;
  char *action_str;
  char action = '\0';

  while (!_dbus_string_init (&str))
    _dbus_wait_for_memory ();

  if ((reload_pipe[RELOAD_READ_END] > 0) &&
      _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
    {
      _dbus_warn ("Couldn't read from reload pipe.\n");
      close_reload_pipe (&watch);
      return TRUE;
    }

  action_str = _dbus_string_get_data (&str);
  if (action_str != NULL)
    {
      action = action_str[0];
    }
  _dbus_string_free (&str);

  /* this can only fail if we don't understand the config file
   * or OOM.  Either way we should just stick with the currently
   * loaded config.
   */
  dbus_error_init (&error);

  switch (action)
    {
    case ACTION_RELOAD:
      if (! bus_context_reload_config (context, &error))
        {
          _DBUS_ASSERT_ERROR_IS_SET (&error);
          _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
                        dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
          _dbus_warn ("Unable to reload configuration: %s\n",
                      error.message);
          dbus_error_free (&error);
        }
      break;

    case ACTION_QUIT:
      {
        DBusLoop *loop;
        /*
         * On OSs without abstract sockets, we want to quit
         * gracefully rather than being killed by SIGTERM,
         * so that DBusServer gets a chance to clean up the
         * sockets from the filesystem. fd.o #38656
         */
        loop = bus_context_get_loop (context);
        if (loop != NULL)
          {
            _dbus_loop_quit (loop);
          }
      }
      break;

    default:
      break;
    }

  return TRUE;
}
コード例 #28
0
ファイル: dbus-nonce.c プロジェクト: scottt/dbus-vmci
static dbus_bool_t
do_noncefile_create (DBusNonceFile *noncefile,
                     DBusError *error,
                     dbus_bool_t use_subdir)
{
    dbus_bool_t ret;
    DBusString randomStr;

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    _dbus_assert (noncefile);

    if (!_dbus_string_init (&randomStr))
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto on_error;
      }

    if (!_dbus_generate_random_ascii (&randomStr, 8))
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto on_error;
      }

    if (!_dbus_string_init (&noncefile->dir)
        || !_dbus_string_append (&noncefile->dir, _dbus_get_tmpdir()))
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto on_error;
      }
    if (use_subdir)
      {
        if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-")
            || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) )
          {
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
            goto on_error;
          }
        if (!_dbus_string_init (&noncefile->path)
            || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
            || !_dbus_string_append (&noncefile->dir, "/nonce"))
          {
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
            goto on_error;
          }
        if (!_dbus_create_directory (&noncefile->dir, error))
          {
            _DBUS_ASSERT_ERROR_IS_SET (error);
            goto on_error;
          }
        _DBUS_ASSERT_ERROR_IS_CLEAR (error);

      }
    else
      {
        if (!_dbus_string_init (&noncefile->path)
            || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
            || !_dbus_string_append (&noncefile->path, "/dbus_nonce-")
            || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr)))
          {
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
            goto on_error;
          }

      }

    if (!generate_and_write_nonce (&noncefile->path, error))
      {
        _DBUS_ASSERT_ERROR_IS_SET (error);
        if (use_subdir)
          _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead
        goto on_error;
      }
    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    _dbus_string_free (&randomStr);

    return TRUE;
  on_error:
    if (use_subdir)
      _dbus_delete_directory (&noncefile->dir, NULL);
    _dbus_string_free (&noncefile->dir);
    _dbus_string_free (&noncefile->path);
    _dbus_string_free (&randomStr);
    return FALSE;
}
コード例 #29
0
/**
 * Creates a new transport for the given hostname and port.
 * If host is NULL, it will default to localhost
 *
 * @param host the host to connect to
 * @param port the port to connect to
 * @param family the address family to connect to
 * @param noncefile path to nonce file
 * @param error location to store reason for failure.
 * @returns a new transport, or #NULL on failure.
 */
DBusTransport*
_dbus_transport_new_for_tcp_socket (const char     *host,
                                    const char     *port,
                                    const char     *family,
                                    const char     *noncefile,
                                    DBusError      *error)
{
  DBusSocket fd;
  DBusTransport *transport;
  DBusString address;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  if (host == NULL)
    host = "localhost";

  if (!_dbus_string_append (&address, noncefile ? "nonce-tcp:" : "tcp:"))
    goto error;

  if (!_dbus_string_append (&address, "host=") ||
      !_dbus_string_append (&address, host))
    goto error;

  if (!_dbus_string_append (&address, ",port=") ||
      !_dbus_string_append (&address, port))
    goto error;

  if (family != NULL &&
      (!_dbus_string_append (&address, ",family=") ||
       !_dbus_string_append (&address, family)))
    goto error;

  if (noncefile != NULL &&
      (!_dbus_string_append (&address, ",noncefile=") ||
       !_dbus_string_append (&address, noncefile)))
    goto error;

  fd = _dbus_connect_tcp_socket_with_nonce (host, port, family, noncefile, error);
  if (!_dbus_socket_is_valid (fd))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _dbus_string_free (&address);
      return NULL;
    }

  _dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
                 host, port);
  
  transport = _dbus_transport_new_for_socket (fd, NULL, &address);
  _dbus_string_free (&address);
  if (transport == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_close_socket (fd, NULL);
      _dbus_socket_invalidate (&fd);
    }

  return transport;

error:
  _dbus_string_free (&address);
  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  return NULL;
}
コード例 #30
0
ファイル: dbus-spawn.c プロジェクト: d-bus/dbus
/**
 * Spawns a new process.
 *
 * On Unix platforms, the child_setup function is passed the given
 * user_data and is run in the child after fork() but before calling exec().
 * This can be used to change uid, resource limits and so on.
 * On Windows, this functionality does not fit the multi-processing model
 * (Windows does the equivalent of fork() and exec() in a single API call),
 * and the child_setup function and its user_data are ignored.
 *
 * Also creates a "babysitter" which tracks the status of the
 * child process, advising the parent if the child exits.
 * If the spawn fails, no babysitter is created.
 * If sitter_p is #NULL, no babysitter is kept.
 *
 * @param sitter_p return location for babysitter or #NULL
 * @param log_name the name under which to log messages about this process being spawned
 * @param argv the executable and arguments
 * @param env the environment, or #NULL to copy the parent's
 * @param child_setup function to call in child pre-exec()
 * @param user_data user data for setup function
 * @param error error object to be filled in if function fails
 * @returns #TRUE on success, #FALSE if error is filled in
 */
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   const char               *log_name,
                                   char             * const *argv,
                                   char                    **env,
                                   DBusSpawnFlags            flags,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{
  DBusBabysitter *sitter;
  int child_err_report_pipe[2] = { -1, -1 };
  DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
  pid_t pid;
#ifdef HAVE_SYSTEMD
  int fd_out = -1;
  int fd_err = -1;
#endif
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _dbus_assert (argv[0] != NULL);

  if (sitter_p != NULL)
    *sitter_p = NULL;

  sitter = NULL;

  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  sitter->log_name = _dbus_strdup (log_name);
  if (sitter->log_name == NULL && log_name != NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  if (sitter->log_name == NULL)
    sitter->log_name = _dbus_strdup (argv[0]);

  if (sitter->log_name == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
  
  if (!make_pipe (child_err_report_pipe, error))
    goto cleanup_and_fail;

  if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
    goto cleanup_and_fail;

  /* Setting up the babysitter is only useful in the parent,
   * but we don't want to run out of memory and fail
   * after we've already forked, since then we'd leak
   * child processes everywhere.
   */
  sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                         DBUS_WATCH_READABLE,
                                         TRUE, handle_watch, sitter, NULL);
  if (sitter->error_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
        
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->error_watch);
      _dbus_watch_unref (sitter->error_watch);
      sitter->error_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  if (sitter->sitter_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->sitter_watch);
      _dbus_watch_unref (sitter->sitter_watch);
      sitter->sitter_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

#ifdef HAVE_SYSTEMD
  if (flags & DBUS_SPAWN_REDIRECT_OUTPUT)
    {
      /* This may fail, but it's not critical.
       * In particular, if we were compiled with journald support but are now
       * running on a non-systemd system, this is going to fail, so we
       * have to cope gracefully. */
      fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
      fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
    }
#endif

  pid = fork ();
  
  if (pid < 0)
    {
      dbus_set_error (error,
		      DBUS_ERROR_SPAWN_FORK_FAILED,
		      "Failed to fork (%s)",
		      _dbus_strerror (errno));
      goto cleanup_and_fail;
    }
  else if (pid == 0)
    {
      /* Immediate child, this is the babysitter process. */
      int grandchild_pid;
      
      /* Be sure we crash if the parent exits
       * and we write to the err_report_pipe
       */
      signal (SIGPIPE, SIG_DFL);

      /* Close the parent's end of the pipes. */
      close_and_invalidate (&child_err_report_pipe[READ_END]);
      close_and_invalidate (&babysitter_pipe[0].fd);
      
      /* Create the child that will exec () */
      grandchild_pid = fork ();
      
      if (grandchild_pid < 0)
	{
	  write_err_and_exit (babysitter_pipe[1].fd,
			      CHILD_FORK_FAILED);
          _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
	}
      else if (grandchild_pid == 0)
      {
#ifdef __linux__
          int fd = -1;

#ifdef O_CLOEXEC
          fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
#endif

          if (fd < 0)
            {
              fd = open ("/proc/self/oom_score_adj", O_WRONLY);
              _dbus_fd_set_close_on_exec (fd);
            }

          if (fd >= 0)
            {
              if (write (fd, "0", sizeof (char)) < 0)
                _dbus_warn ("writing oom_score_adj error: %s", strerror (errno));
              _dbus_close (fd, NULL);
            }
#endif
          /* Go back to ignoring SIGPIPE, since it's evil
           */
          signal (SIGPIPE, SIG_IGN);

          close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
	  /* log to systemd journal if possible */
	  if (fd_out >= 0)
            dup2 (fd_out, STDOUT_FILENO);
	  if (fd_err >= 0)
            dup2 (fd_err, STDERR_FILENO);
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
	  do_exec (child_err_report_pipe[WRITE_END],
		   argv,
		   env,
		   child_setup, user_data);
          _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
	}
      else
	{
          close_and_invalidate (&child_err_report_pipe[WRITE_END]);
#ifdef HAVE_SYSTEMD
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
          babysit (grandchild_pid, babysitter_pipe[1].fd);
          _dbus_assert_not_reached ("Got to code after babysit()");
	}
    }
  else
    {      
      /* Close the uncared-about ends of the pipes */
      close_and_invalidate (&child_err_report_pipe[WRITE_END]);
      close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
      close_and_invalidate (&fd_out);
      close_and_invalidate (&fd_err);
#endif

      sitter->socket_to_babysitter = babysitter_pipe[0];
      babysitter_pipe[0].fd = -1;
      
      sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
      child_err_report_pipe[READ_END] = -1;

      sitter->sitter_pid = pid;

      if (sitter_p != NULL)
        *sitter_p = sitter;
      else
        _dbus_babysitter_unref (sitter);

      dbus_free_string_array (env);

      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      
      return TRUE;
    }

 cleanup_and_fail:

  _DBUS_ASSERT_ERROR_IS_SET (error);
  
  close_and_invalidate (&child_err_report_pipe[READ_END]);
  close_and_invalidate (&child_err_report_pipe[WRITE_END]);
  close_and_invalidate (&babysitter_pipe[0].fd);
  close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
  close_and_invalidate (&fd_out);
  close_and_invalidate (&fd_err);
#endif

  if (sitter != NULL)
    _dbus_babysitter_unref (sitter);
  
  return FALSE;
}