Exemplo n.º 1
0
void
arv_rtkit_make_high_priority (GDBusConnection *connection, pid_t thread, int nice_level, GError **error)
{
	GDBusMessage *message;
	GDBusMessage *reply;
	GError *local_error = NULL;

	message = g_dbus_message_new_method_call (RTKIT_SERVICE_NAME,
						  RTKIT_OBJECT_PATH,
						  "org.freedesktop.RealtimeKit1",
						  "MakeThreadHighPriority");
	g_dbus_message_set_body (message, g_variant_new ("(ti)", thread, nice_level));

	reply = g_dbus_connection_send_message_with_reply_sync (connection, message,
								G_DBUS_SEND_MESSAGE_FLAGS_NONE, 1000, NULL, NULL,
								&local_error);
	g_object_unref (message);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	if (g_dbus_message_get_message_type (reply) != G_DBUS_MESSAGE_TYPE_METHOD_RETURN) {
		local_error = g_error_new (ARV_RTKIT_ERROR, 0, "%s", g_dbus_message_get_error_name (reply));
		g_propagate_error (error, local_error);
		g_object_unref (reply);
		return;
	}

	g_object_unref (reply);
}
Exemplo n.º 2
0
// returns object path of default adapter or NULL if failed
// this object path must be freed with g_free()
gchar* bluez_get_default_adapter(GDBusConnection* conn)
{
    GError* error = NULL;

    GDBusMessage* call_message = g_dbus_message_new_method_call("org.bluez",
                                                       "/",
                                                       "org.bluez.Manager",
                                                       "DefaultAdapter");
    if(call_message == NULL)
    {
        g_printf("g_dbus_message_new_method_call failed\n");

        return NULL;
    }

    GDBusMessage* reply_message = g_dbus_connection_send_message_with_reply_sync(conn,
                                                                          call_message,
                                                                          G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                                          -1,
                                                                          NULL,
                                                                          NULL,
                                                                          &error);
    if(reply_message == NULL)
    {
        g_printf("g_dbus_connection_send_message_with_reply_sync failed\n");

        return NULL;
    }

    if(g_dbus_message_get_message_type(reply_message) == G_DBUS_MESSAGE_TYPE_ERROR)
    {
        printf("Error occured\n");

        g_dbus_message_to_gerror(reply_message, &error);
        g_printerr("Error invoking g_dbus_connection_send_message_with_reply_sync: %s\n", error->message);

        g_error_free(error);

        return NULL;
    }


    GVariant* variant = g_dbus_message_get_body(reply_message);

    // get first child, as this is the object path of the default interface of bluez
    GVariant* var_child = g_variant_get_child_value(variant, 0);

    const gchar* tmp_path = g_variant_get_string(var_child, NULL);

    // copy content of tmp_path to obj_path, as tmp_path gets freed after unref of the variant
    gchar* obj_path = g_strdup(tmp_path);

    // cleanup
    g_variant_unref(var_child);

    g_object_unref(call_message);
    g_object_unref(reply_message);

    return obj_path;
}
Exemplo n.º 3
0
static char *
xdp_connection_lookup_app_id_sync (GDBusConnection       *connection,
                                   const char            *sender,
                                   GCancellable          *cancellable,
                                   GError               **error)
{
  g_autoptr(GDBusMessage) msg = NULL;
  g_autoptr(GDBusMessage) reply = NULL;
  char *app_id = NULL;
  GVariant *body;
  guint32 pid;

  G_LOCK (app_ids);
  if (app_ids)
    app_id = g_strdup (g_hash_table_lookup (app_ids, sender));
  G_UNLOCK (app_ids);

  if (app_id != NULL)
    return app_id;

  msg = g_dbus_message_new_method_call ("org.freedesktop.DBus",
                                        "/org/freedesktop/DBus",
                                        "org.freedesktop.DBus",
                                        "GetConnectionUnixProcessID");
  g_dbus_message_set_body (msg, g_variant_new ("(s)", sender));

  reply = g_dbus_connection_send_message_with_reply_sync (connection, msg,
                                                          G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                          30000,
                                                          NULL,
                                                          cancellable,
                                                          error);
  if (reply == NULL)
    return NULL;

  if (g_dbus_message_get_message_type (reply) == G_DBUS_MESSAGE_TYPE_ERROR)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find peer app id");
      return NULL;
    }

  body = g_dbus_message_get_body (reply);

  g_variant_get (body, "(u)", &pid);

  app_id = get_app_id_from_pid (pid, error);
  if (app_id)
    {
      G_LOCK (app_ids);
      ensure_app_ids ();
      g_hash_table_insert (app_ids, g_strdup (sender), g_strdup (app_id));
      G_UNLOCK (app_ids);
    }

  return app_id;
}
static GDBusMessage *
screensaver_send_message_void (GDBusConnection *connection,
                               const char      *name,
                               gboolean         expect_reply)
{
        GDBusMessage *message, *reply;
        GError       *error;

        g_return_val_if_fail (connection != NULL, NULL);
        g_return_val_if_fail (name != NULL, NULL);

        message = g_dbus_message_new_method_call (GS_SERVICE,
                                                  GS_PATH,
                                                  GS_INTERFACE,
                                                  name);
        if (message == NULL) {
                g_warning ("Couldn't allocate the dbus message");
                return NULL;
        }

        error = NULL;

        if (! expect_reply) {
                reply = NULL;

                g_dbus_connection_send_message (connection,
                                                message,
                                                G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                NULL,
                                                &error);

        } else {
                reply = g_dbus_connection_send_message_with_reply_sync (connection,
                                                                        message,
                                                                        G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                                        -1,
                                                                        NULL,
                                                                        NULL,
                                                                        &error);
        }

        if (error != NULL) {
                g_warning ("unable to send message: %s", error->message);
                g_clear_error (&error);
        }

        g_dbus_connection_flush_sync (connection, NULL, &error);
        if (error != NULL) {
                g_warning ("unable to flush message queue: %s", error->message);
                g_clear_error (&error);
        }

        g_object_unref (message);

        return reply;
}
Exemplo n.º 5
0
void bluez_unregister_watcher(GDBusConnection* conn, const gchar* service_path)
{
    GError* error = NULL;

    GDBusMessage* call_message = g_dbus_message_new_method_call("org.bluez",
                                                       service_path,
                                                       "org.bluez.Characteristic",
                                                       "UnregisterCharacteristicsWatcher");
    if(call_message == NULL)
    {
        printf("g_dbus_message_new_method_call failed\n");

        return;
    }

    gchar path[255];
    g_snprintf(path, 255, "/test/bluez/%d", getpid());

    GVariant* variant_addr = g_variant_new_object_path(path);
    GVariant* variant_body = g_variant_new_tuple(&variant_addr, 1);

    g_dbus_message_set_body(call_message, variant_body);

    GDBusMessage* reply_message = g_dbus_connection_send_message_with_reply_sync(conn,
                                                                          call_message,
                                                                          G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                                          -1,
                                                                          NULL,
                                                                          NULL,
                                                                          &error);
    if(reply_message == NULL)
    {
        printf("g_dbus_connection_send_message_with_reply_sync failed\n");

        return;
    }

    if(g_dbus_message_get_message_type(reply_message) == G_DBUS_MESSAGE_TYPE_ERROR)
    {
        printf("Error occured\n");

        g_dbus_message_to_gerror(reply_message, &error);
        g_printerr("Error invoking g_dbus_connection_send_message_with_reply_sync: %s\n", error->message);

        g_error_free(error);

        return;
    }

    // cleanup
    g_object_unref(call_message);
    g_object_unref(reply_message);
}
Exemplo n.º 6
0
GVariant* bluez_characteristic_get_value(GDBusConnection* conn, const gchar* char_path)
{
    GError* error = NULL;

    GDBusMessage* call_message = g_dbus_message_new_method_call("org.bluez",
                                                       char_path,
                                                       "org.bluez.Characteristic",
                                                       "GetProperties");
    if(call_message == NULL)
    {
        g_printf("g_dbus_message_new_method_call failed\n");

        return NULL;
    }

    GDBusMessage* reply_message = g_dbus_connection_send_message_with_reply_sync(conn,
                                                                          call_message,
                                                                          G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                                          -1,
                                                                          NULL,
                                                                          NULL,
                                                                          &error);
    if(reply_message == NULL)
    {
        g_printf("g_dbus_connection_send_message_with_reply_sync failed\n");

        return NULL;
    }

    if(g_dbus_message_get_message_type(reply_message) == G_DBUS_MESSAGE_TYPE_ERROR)
    {
        g_printf("Error occured\n");

        g_dbus_message_to_gerror(reply_message, &error);
        g_printerr("Error invoking g_dbus_connection_send_message_with_reply_sync: %s\n", error->message);

        g_error_free(error);

        return NULL;
    }



    GVariant* var_body = g_dbus_message_get_body(reply_message);

    g_variant_ref(var_body);

    // cleanup
    g_object_unref(call_message);
    g_object_unref(reply_message);

    return var_body;
}
Exemplo n.º 7
0
// returns the object path to a given device or NULL if failed
// object path has to be freed with g_free()
gchar* bluez_find_device(GDBusConnection* conn, const gchar* adapter_path, const char* bt_addr)
{
    GError* error = NULL;

    GDBusMessage* call_message = g_dbus_message_new_method_call("org.bluez",
                                                       adapter_path,
                                                       "org.bluez.Adapter",
                                                       "FindDevice");
    if(call_message == NULL)
    {
        return NULL;
    }

    GVariant* variant_addr = g_variant_new_string(bt_addr);
    GVariant* variant_body = g_variant_new_tuple(&variant_addr, 1);

    g_dbus_message_set_body(call_message, variant_body);

    GDBusMessage* reply_message = g_dbus_connection_send_message_with_reply_sync(conn,
                                                                          call_message,
                                                                          G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                                          -1,
                                                                          NULL,
                                                                          NULL,
                                                                          &error);
    if(reply_message == NULL)
    {
        return NULL;
    }

    if(g_dbus_message_get_message_type(reply_message) == G_DBUS_MESSAGE_TYPE_ERROR)
    {
        return NULL;
    }

    GVariant* variant = g_dbus_message_get_body(reply_message);

    // get first child, as this is the object path of the default interface of bluez
    GVariant* var_child = g_variant_get_child_value(variant, 0);

    const gchar* tmp_path = g_variant_get_string(var_child, NULL);

    // copy content of tmp_path to obj_path, as tmp_path gets freed after unref of the variant
    gchar* obj_path = g_strdup(tmp_path);

    // cleanup
    g_variant_unref(var_child);

    g_object_unref(call_message);
    g_object_unref(reply_message);

    return obj_path;
}
static
int
is_dbus_based_screensaver_active(const char *d_service, const char *d_path,
                                 const char *d_interface)
{
    GDBusMessage *msg = NULL;
    GDBusMessage *reply = NULL;
    uint32_t ret = 0;

    assert(connection);

    // detect is screen saver already active
    msg = g_dbus_message_new_method_call(d_service, d_path, d_interface, "GetActive");
    if (!msg) {
        trace_error("%s, can't allocate GDBusMessage\n", __func__);
        goto err;
    }

    GError *error = NULL;
    reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
                                                           G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1,
                                                           NULL, NULL, &error);
    if (error) {
        trace_error("%s, can't send message, %s\n", __func__, error->message);
        g_clear_error(&error);
        goto err;
    }

    g_dbus_connection_flush_sync(connection, NULL, &error);
    if (error != NULL) {
        trace_error("%s, can't flush dbus connection, %s\n", __func__, error->message);
        g_clear_error(&error);
        goto err;
    }

    GVariant *v = g_dbus_message_get_body(reply);
    v = g_variant_get_child_value(v, 0);
    if (g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN))
        ret = g_variant_get_boolean(v);
    else
        ret = 0;

err:
    if (reply)
        g_object_unref(reply);

    if (msg)
        g_object_unref(msg);

    return ret;
}
/* see gdbus-example-server.c for the server implementation */
static gint
get_server_stdout (GDBusConnection  *connection,
                   const gchar      *name_owner,
                   GError          **error)
{
  GDBusMessage *method_call_message;
  GDBusMessage *method_reply_message;
  GUnixFDList *fd_list;
  gint fd;

  fd = -1;
  method_call_message = NULL;
  method_reply_message = NULL;

  method_call_message = g_dbus_message_new_method_call (name_owner,
                                                        "/org/gtk/GDBus/TestObject",
                                                        "org.gtk.GDBus.TestInterface",
                                                        "GimmeStdout");
  method_reply_message = g_dbus_connection_send_message_with_reply_sync (connection,
                                                                         method_call_message,
                                                                         -1,
                                                                         NULL, /* out_serial */
                                                                         NULL, /* cancellable */
                                                                         error);
  if (method_reply_message == NULL)
      goto out;

  if (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_ERROR)
    {
      g_dbus_message_to_gerror (method_reply_message, error);
      goto out;
    }

  fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
  fd = g_unix_fd_list_get (fd_list, 0, error);

 out:
  g_object_unref (method_call_message);
  g_object_unref (method_reply_message);

  return fd;
}
Exemplo n.º 10
0
static void steadyflow_iapp_service_proxy_set_visible (SteadyflowIAppService* self, gboolean visible, GError** error) {
	GDBusMessage *_message;
	GVariant *_arguments;
	GVariantBuilder _arguments_builder;
	GDBusMessage *_reply_message;
	G_IO_ERROR;
	_message = g_dbus_message_new_method_call (g_dbus_proxy_get_name ((GDBusProxy *) self), g_dbus_proxy_get_object_path ((GDBusProxy *) self), "net.launchpad.steadyflow.App", "SetVisible");
	g_variant_builder_init (&_arguments_builder, G_VARIANT_TYPE_TUPLE);
	g_variant_builder_add_value (&_arguments_builder, g_variant_new_boolean (visible));
	_arguments = g_variant_builder_end (&_arguments_builder);
	g_dbus_message_set_body (_message, _arguments);
	_reply_message = g_dbus_connection_send_message_with_reply_sync (g_dbus_proxy_get_connection ((GDBusProxy *) self), _message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, g_dbus_proxy_get_default_timeout ((GDBusProxy *) self), NULL, NULL, error);
	g_object_unref (_message);
	if (!_reply_message) {
		return;
	}
	if (g_dbus_message_to_gerror (_reply_message, error)) {
		g_object_unref (_reply_message);
		return;
	}
	g_object_unref (_reply_message);
}
static
uint32_t
detect_dbus_based_screensavers(void)
{
    GDBusMessage *msg, *reply;
    uint32_t ret;

    assert(connection);

    // enumerate all services
    msg = g_dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
                                         "org.freedesktop.DBus", "ListNames");
    if (!msg) {
        trace_error("%s, can't allocate GDBusMessage\n", __func__);
        ret = 0;
        goto err_1;
    }

    GError *error = NULL;
    reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
                                                           G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1,
                                                           NULL, NULL, &error);
    if (error != NULL) {
        trace_error("%s, can't send message, %s\n", __func__, error->message);
        g_clear_error(&error);
        ret = 0;
        goto err_2;
    }

    g_dbus_connection_flush_sync(connection, NULL, &error);
    if (error != NULL) {
        trace_error("%s, can't flush dbus connection, %s\n", __func__, error->message);
        g_clear_error(&error);
        ret = 0;
        goto err_3;
    }

    // iterate over the list
    GVariant *v = g_dbus_message_get_body(reply);
    GVariantIter *iter;
    gchar *str;

    uint32_t flags = 0;
    g_variant_get(v, "(as)", &iter);
    while (g_variant_iter_loop(iter, "s", &str)) {
        if (strcmp(str, GS_SERVICE) == 0)
            flags |= SST_GNOME_SCREENSAVER;

        if (strcmp(str, KS_SERVICE) == 0)
            flags |= SST_KDE_SCREENSAVER;

        if (strcmp(str, FDOS_SERVICE) == 0)
            flags |= SST_FDO_SCREENSAVER;

        if (strcmp(str, CINNAMON_SERVICE) == 0)
            flags |= SST_CINNAMON_SCREENSAVER;
    }
    g_variant_iter_free(iter);
    ret = flags;

err_3:
    g_object_unref(reply);
err_2:
    g_object_unref(msg);
err_1:
    return ret;
}
Exemplo n.º 12
0
static gint64
arv_rtkit_get_int_property (GDBusConnection *connection, const char* propname, GError **error) {

	GDBusMessage *message;
	GDBusMessage *reply;
	GError *local_error = NULL;
	GVariant *body;
	GVariant *parameter;
	GVariant *variant;
	const GVariantType *variant_type;
	gint64 value;

	message = g_dbus_message_new_method_call (RTKIT_SERVICE_NAME,
						  RTKIT_OBJECT_PATH,
						  "org.freedesktop.DBus.Properties",
						  "Get");
	g_dbus_message_set_body (message, g_variant_new ("(ss)", "org.freedesktop.RealtimeKit1", propname));

	reply = g_dbus_connection_send_message_with_reply_sync (connection, message,
								G_DBUS_SEND_MESSAGE_FLAGS_NONE, 1000, NULL, NULL,
								&local_error);
	g_object_unref (message);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return 0;
	}

	if (g_dbus_message_get_message_type (reply) != G_DBUS_MESSAGE_TYPE_METHOD_RETURN) {
		local_error = g_error_new (ARV_RTKIT_ERROR, ARV_RTKIT_ERROR_PERMISSION_DENIED,
					   "%s", g_dbus_message_get_error_name (reply));
		g_propagate_error (error, local_error);
		g_object_unref (reply);
		return 0;
	}

	if (!g_variant_type_equal ("v", g_dbus_message_get_signature (reply))) {
		local_error = g_error_new (ARV_RTKIT_ERROR, ARV_RTKIT_ERROR_WRONG_REPLY,
					   "Invalid reply signature");
		g_propagate_error (error, local_error);
		g_object_unref (reply);
		return 0;
	}

	body = g_dbus_message_get_body (reply);
	parameter = g_variant_get_child_value (body, 0);
	variant = g_variant_get_variant (parameter);

	variant_type = g_variant_get_type (variant);

	if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32))
		value = g_variant_get_int32 (variant);
	else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64))
		value = g_variant_get_int64 (variant);
	else
		value = 0;

	g_variant_unref (parameter);
	g_variant_unref (variant);
	g_object_unref (reply);

	return value;
}
Exemplo n.º 13
0
/**
 * fu_util_get_details:
 **/
static gboolean
fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error)
{
	GVariant *body;
	GVariant *val;
	gint fd;
	gint retval;
	_cleanup_object_unref_ GDBusMessage *message = NULL;
	_cleanup_object_unref_ GDBusMessage *request = NULL;
	_cleanup_object_unref_ GUnixFDList *fd_list = NULL;

	/* check args */
	if (g_strv_length (values) != 1) {
		g_set_error_literal (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INTERNAL,
				     "Invalid arguments: expected 'filename'");
		return FALSE;
	}

	/* open file */
	fd = open (values[0], O_RDONLY);
	if (fd < 0) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INVALID_FILE,
			     "failed to open %s",
			     values[0]);
		return FALSE;
	}

	/* set out of band file descriptor */
	fd_list = g_unix_fd_list_new ();
	retval = g_unix_fd_list_append (fd_list, fd, NULL);
	g_assert (retval != -1);
	request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE,
						  FWUPD_DBUS_PATH,
						  FWUPD_DBUS_INTERFACE,
						  "GetDetails");
	g_dbus_message_set_unix_fd_list (request, fd_list);

	/* g_unix_fd_list_append did a dup() already */
	close (fd);

	/* send message */
	body = g_variant_new ("(h)", fd > -1 ? 0 : -1);
	g_dbus_message_set_body (request, body);
	message = g_dbus_connection_send_message_with_reply_sync (priv->conn,
								  request,
								  G_DBUS_SEND_MESSAGE_FLAGS_NONE,
								  -1,
								  NULL,
								  NULL,
								  error);
	if (message == NULL) {
		g_dbus_error_strip_remote_error (*error);
		return FALSE;
	}
	if (g_dbus_message_to_gerror (message, error)) {
		g_dbus_error_strip_remote_error (*error);
		return FALSE;
	}

	/* print results */
	val = g_dbus_message_get_body (message);
	fu_util_print_metadata (val);
	return TRUE;
}
Exemplo n.º 14
0
gboolean
e_mapi_util_trigger_krb_auth (const EMapiProfileData *empd,
			      GError **error)
{
	gint success = FALSE;
	GError *local_error = NULL;
	GDBusConnection *connection;
	GDBusMessage *message, *reply;
	gchar *name;

	connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
	if (local_error) {
		g_warning ("could not get system bus: %s\n",
			   local_error->message);
		g_propagate_error (error, local_error);
		return FALSE;
	}

	g_dbus_connection_set_exit_on_close (connection, FALSE);
	/* Create a new message on the KRB_DBUS_INTERFACE */
	message = g_dbus_message_new_method_call (KRB_DBUS_INTERFACE,
						  KRB_DBUS_PATH,
						  KRB_DBUS_INTERFACE,
						  "acquireTgt");
	if (!message) {
		g_object_unref (connection);
		return FALSE;
	}

	/* Appends the data as an argument to the message */
	name = g_strdup_printf ("%s@%s", empd->username, empd->krb_realm);
	g_dbus_message_set_body (message, g_variant_new ("(s)", name));

	/* Sends the message: Have a 300 sec wait timeout  */
	reply = g_dbus_connection_send_message_with_reply_sync (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 300 * 1000, NULL, NULL, &local_error);
	g_free (name);

	if (!local_error && reply) {
		if (g_dbus_message_to_gerror (reply, &local_error)) {
			g_object_unref (reply);
			reply = NULL;
		}
	}

	if (local_error) {
		g_dbus_error_strip_remote_error (local_error);
		g_propagate_error (error, local_error);
	}

	if (reply) {
		GVariant *body = g_dbus_message_get_body (reply);
		if (body) {
			g_variant_get (body, "(b)", &success);
		}
		g_object_unref (reply);
	}

	/* Free the message */
	g_object_unref (message);
	g_object_unref (connection);

	return success && !local_error;
}
Exemplo n.º 15
0
gboolean
xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(XdgAppDeploy) app_deploy = NULL;
  g_autoptr(XdgAppDeploy) runtime_deploy = NULL;
  g_autoptr(GFile) app_files = NULL;
  g_autoptr(GFile) runtime_files = NULL;
  g_autoptr(GFile) app_id_dir = NULL;
  g_autoptr(GFile) app_cache_dir = NULL;
  g_autoptr(GFile) app_data_dir = NULL;
  g_autoptr(GFile) app_config_dir = NULL;
  g_autoptr(GFile) home = NULL;
  g_autoptr(GFile) user_font1 = NULL;
  g_autoptr(GFile) user_font2 = NULL;
  g_autoptr(XdgAppSessionHelper) session_helper = NULL;
  g_autofree char *runtime = NULL;
  g_autofree char *default_command = NULL;
  g_autofree char *runtime_ref = NULL;
  g_autofree char *app_ref = NULL;
  g_autofree char *doc_mount_path = NULL;
  g_autoptr(GKeyFile) metakey = NULL;
  g_autoptr(GKeyFile) runtime_metakey = NULL;
  g_autoptr(GPtrArray) argv_array = NULL;
  g_auto(GStrv) envp = NULL;
  g_autoptr(GPtrArray) dbus_proxy_argv = NULL;
  g_autofree char *monitor_path = NULL;
  const char *app;
  const char *branch = "master";
  const char *command = "/bin/sh";
  int i;
  int rest_argv_start, rest_argc;
  int sync_proxy_pipes[2];
  g_autoptr(XdgAppContext) arg_context = NULL;
  g_autoptr(XdgAppContext) app_context = NULL;
  g_autoptr(XdgAppContext) overrides = NULL;
  g_autoptr(GDBusConnection) session_bus = NULL;

  context = g_option_context_new ("APP [args...] - Run an app");

  rest_argc = 0;
  for (i = 1; i < argc; i++)
    {
      /* The non-option is the command, take it out of the arguments */
      if (argv[i][0] != '-')
        {
          rest_argv_start = i;
          rest_argc = argc - i;
          argc = i;
          break;
        }
    }

  arg_context = xdg_app_context_new ();
  g_option_context_add_group (context, xdg_app_context_get_options (arg_context));

  if (!xdg_app_option_context_parse (context, options, &argc, &argv, XDG_APP_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
    return FALSE;

  if (rest_argc == 0)
    return usage_error (context, "APP must be specified", error);

  app = argv[rest_argv_start];

  if (opt_branch)
    branch = opt_branch;

  if (!xdg_app_is_valid_name (app))
    return xdg_app_fail (error, "'%s' is not a valid application name", app);

  if (!xdg_app_is_valid_branch (branch))
    return xdg_app_fail (error, "'%s' is not a valid branch name", branch);

  app_ref = xdg_app_build_app_ref (app, branch, opt_arch);

  app_deploy = xdg_app_find_deploy_for_ref (app_ref, cancellable, error);
  if (app_deploy == NULL)
    return FALSE;

  metakey = xdg_app_deploy_get_metadata (app_deploy);

  argv_array = g_ptr_array_new_with_free_func (g_free);
  dbus_proxy_argv = g_ptr_array_new_with_free_func (g_free);
  g_ptr_array_add (argv_array, g_strdup (HELPER));
  g_ptr_array_add (argv_array, g_strdup ("-l"));

  if (!xdg_app_run_add_extension_args (argv_array, metakey, app_ref, cancellable, error))
    return FALSE;

  if (opt_runtime)
    runtime = opt_runtime;
  else
    {
      runtime = g_key_file_get_string (metakey, "Application", opt_devel ? "sdk" : "runtime", error);
      if (*error)
        return FALSE;
    }

  runtime_ref = g_build_filename ("runtime", runtime, NULL);

  runtime_deploy = xdg_app_find_deploy_for_ref (runtime_ref, cancellable, error);
  if (runtime_deploy == NULL)
    return FALSE;

  runtime_metakey = xdg_app_deploy_get_metadata (runtime_deploy);

  app_context = xdg_app_context_new ();
  if (!xdg_app_context_load_metadata (app_context, runtime_metakey, error))
    return FALSE;
  if (!xdg_app_context_load_metadata (app_context, metakey, error))
    return FALSE;

  overrides = xdg_app_deploy_get_overrides (app_deploy);
  xdg_app_context_merge (app_context, overrides);

  xdg_app_context_merge (app_context, arg_context);

  if (!xdg_app_run_add_extension_args (argv_array, runtime_metakey, runtime_ref, cancellable, error))
    return FALSE;

  if ((app_id_dir = xdg_app_ensure_data_dir (app, cancellable, error)) == NULL)
      return FALSE;

  app_cache_dir = g_file_get_child (app_id_dir, "cache");
  g_ptr_array_add (argv_array, g_strdup ("-B"));
  g_ptr_array_add (argv_array, g_strdup_printf ("/var/cache=%s", gs_file_get_path_cached (app_cache_dir)));

  app_data_dir = g_file_get_child (app_id_dir, "data");
  g_ptr_array_add (argv_array, g_strdup ("-B"));
  g_ptr_array_add (argv_array, g_strdup_printf ("/var/data=%s", gs_file_get_path_cached (app_data_dir)));

  app_config_dir = g_file_get_child (app_id_dir, "config");
  g_ptr_array_add (argv_array, g_strdup ("-B"));
  g_ptr_array_add (argv_array, g_strdup_printf ("/var/config=%s", gs_file_get_path_cached (app_config_dir)));

  app_files = xdg_app_deploy_get_files (app_deploy);
  runtime_files = xdg_app_deploy_get_files (runtime_deploy);

  default_command = g_key_file_get_string (metakey, "Application", "command", error);
  if (*error)
    return FALSE;
  if (opt_command)
    command = opt_command;
  else
    command = default_command;

  session_helper = xdg_app_session_helper_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
								  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
								  "org.freedesktop.XdgApp",
								  "/org/freedesktop/XdgApp/SessionHelper",
								  NULL, NULL);
  if (session_helper &&
      xdg_app_session_helper_call_request_monitor_sync (session_helper,
                                                        &monitor_path,
                                                        NULL, NULL))
    {
      g_ptr_array_add (argv_array, g_strdup ("-m"));
      g_ptr_array_add (argv_array, monitor_path);
    }
  else
    g_ptr_array_add (argv_array, g_strdup ("-r"));

  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
  if (session_bus)
    {
      g_autoptr (GError) local_error = NULL;
      g_autoptr (GDBusMessage) reply = NULL;
      g_autoptr (GDBusMessage) msg = g_dbus_message_new_method_call ("org.freedesktop.portal.Documents",
                                                                     "/org/freedesktop/portal/documents",
                                                                     "org.freedesktop.portal.Documents",
                                                                     "GetMountPoint");
      g_dbus_message_set_body (msg, g_variant_new ("()"));
      reply = g_dbus_connection_send_message_with_reply_sync (session_bus, msg,
                                                              G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                                              30000,
                                                              NULL,
                                                              NULL,
                                                              NULL);
      if (reply)
        {
          if (g_dbus_message_to_gerror (reply, &local_error))
            {
              g_warning ("Can't get document portal: %s\n", local_error->message);
            }
          else
            g_variant_get (g_dbus_message_get_body (reply),
                           "(^ay)", &doc_mount_path);
        }
    }

  xdg_app_run_add_environment_args (argv_array, dbus_proxy_argv, doc_mount_path,
                                    app, app_context, app_id_dir);

  g_ptr_array_add (argv_array, g_strdup ("-b"));
  g_ptr_array_add (argv_array, g_strdup_printf ("/run/host/fonts=%s", SYSTEM_FONTS_DIR));

  if (opt_devel)
    g_ptr_array_add (argv_array, g_strdup ("-c"));

  home = g_file_new_for_path (g_get_home_dir ());
  user_font1 = g_file_resolve_relative_path (home, ".local/share/fonts");
  user_font2 = g_file_resolve_relative_path (home, ".fonts");

  if (g_file_query_exists (user_font1, NULL))
    {
      g_autofree char *path = g_file_get_path (user_font1);
      g_ptr_array_add (argv_array, g_strdup ("-b"));
      g_ptr_array_add (argv_array, g_strdup_printf ("/run/host/user-fonts=%s", path));
    }
  else if (g_file_query_exists (user_font2, NULL))
    {
      g_autofree char *path = g_file_get_path (user_font2);
      g_ptr_array_add (argv_array, g_strdup ("-b"));
      g_ptr_array_add (argv_array, g_strdup_printf ("/run/host/user-fonts=%s", path));
    }

  /* Must run this before spawning the dbus proxy, to ensure it
     ends up in the app cgroup */
  xdg_app_run_in_transient_unit (app);

  if (dbus_proxy_argv->len > 0)
    {
      char x;

      if (pipe (sync_proxy_pipes) < 0)
	{
	  g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "Unable to create sync pipe");
	  return FALSE;
	}

      g_ptr_array_insert (dbus_proxy_argv, 0, g_strdup (DBUSPROXY));
      g_ptr_array_insert (dbus_proxy_argv, 1, g_strdup_printf ("--fd=%d", sync_proxy_pipes[1]));

      g_ptr_array_add (dbus_proxy_argv, NULL); /* NULL terminate */

      if (!g_spawn_async (NULL,
			  (char **)dbus_proxy_argv->pdata,
			  NULL,
			  G_SPAWN_SEARCH_PATH,
			  dbus_spawn_child_setup,
			  GINT_TO_POINTER (sync_proxy_pipes[1]),
			  NULL, error))
	return FALSE;

      close (sync_proxy_pipes[1]);

      /* Sync with proxy, i.e. wait until its listening on the sockets */
      if (read (sync_proxy_pipes[0], &x, 1) != 1)
	{
	  g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "Failed to sync with dbus proxy");
	  return FALSE;
	}

      g_ptr_array_add (argv_array, g_strdup ("-S"));
      g_ptr_array_add (argv_array, g_strdup_printf ("%d", sync_proxy_pipes[0]));
    }

  g_ptr_array_add (argv_array, g_strdup ("-a"));
  g_ptr_array_add (argv_array, g_file_get_path (app_files));
  g_ptr_array_add (argv_array, g_strdup ("-I"));
  g_ptr_array_add (argv_array, g_strdup (app));
  g_ptr_array_add (argv_array, g_file_get_path (runtime_files));

  g_ptr_array_add (argv_array, g_strdup (command));
  for (i = 1; i < rest_argc; i++)
    g_ptr_array_add (argv_array, g_strdup (argv[rest_argv_start + i]));

  g_ptr_array_add (argv_array, NULL);

  envp = g_get_environ ();
  envp = xdg_app_run_apply_env_default (envp);

  envp = xdg_app_run_apply_env_vars (envp, app_context);

  envp = xdg_app_run_apply_env_appid (envp, app_id_dir);

  if (execvpe (HELPER, (char **)argv_array->pdata, envp) == -1)
    {
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "Unable to start app");
      return FALSE;
    }

  /* Not actually reached... */
  return TRUE;
}