#include "config.h" #include #include #include #include "xdp-error.h" static GHashTable *app_ids; typedef struct { char *name; char *app_id; gboolean exited; GList *pending; } AppIdInfo; static void app_id_info_free (AppIdInfo *info) { g_free (info->name); g_free (info->app_id); g_free (info); } static void ensure_app_ids (void) { if (app_ids == NULL) app_ids = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)app_id_info_free); } static void got_credentials_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { AppIdInfo *info = user_data; g_autoptr (GDBusMessage) reply = NULL; g_autoptr (GError) error = NULL; GList *l; reply = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source_object), res, &error); if (!info->exited && reply != NULL) { GVariant *body = g_dbus_message_get_body (reply); guint32 pid; g_autofree char *path = NULL; g_autofree char *content = NULL; g_variant_get (body, "(u)", &pid); path = g_strdup_printf ("/proc/%u/cgroup", pid); if (g_file_get_contents (path, &content, NULL, NULL)) { gchar **lines = g_strsplit (content, "\n", -1); int i; for (i = 0; lines[i] != NULL; i++) { if (g_str_has_prefix (lines[i], "1:name=systemd:")) { const char *unit = lines[i] + strlen ("1:name=systemd:"); g_autofree char *scope = g_path_get_basename (unit); if (g_str_has_prefix (scope, "xdg-app-") && g_str_has_suffix (scope, ".scope")) { const char *name = scope + strlen("xdg-app-"); char *dash = strchr (name, '-'); if (dash != NULL) { *dash = 0; info->app_id = g_strdup (name); } } else info->app_id = g_strdup (""); } } g_strfreev (lines); } } for (l = info->pending; l != NULL; l = l->next) { GTask *task = l->data; if (info->app_id == NULL) g_task_return_new_error (task, XDP_ERROR, XDP_ERROR_FAILED, "Can't find app id"); else g_task_return_pointer (task, g_strdup (info->app_id), g_free); } g_list_free_full (info->pending, g_object_unref); info->pending = NULL; if (info->app_id == NULL) g_hash_table_remove (app_ids, info->name); } void xdp_invocation_lookup_app_id (GDBusMethodInvocation *invocation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation); const gchar *sender = g_dbus_method_invocation_get_sender (invocation); g_autoptr(GTask) task = NULL; AppIdInfo *info; task = g_task_new (invocation, cancellable, callback, user_data); ensure_app_ids (); info = g_hash_table_lookup (app_ids, sender); if (info == NULL) { info = g_new0 (AppIdInfo, 1); info->name = g_strdup (sender); g_hash_table_insert (app_ids, info->name, info); } if (info->app_id) g_task_return_pointer (task, g_strdup (info->app_id), g_free); else { if (info->pending == NULL) { g_autoptr (GDBusMessage) 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)); g_dbus_connection_send_message_with_reply (connection, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 30000, NULL, cancellable, got_credentials_cb, info); } info->pending = g_list_prepend (info->pending, g_object_ref (task)); } } char * xdp_invocation_lookup_app_id_finish (GDBusMethodInvocation *invocation, GAsyncResult *result, GError **error) { return g_task_propagate_pointer (G_TASK (result), error); } static void name_owner_changed (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { const char *name, *from, *to; g_variant_get (parameters, "(sss)", &name, &from, &to); ensure_app_ids (); if (name[0] == ':' && strcmp (name, from) == 0 && strcmp (to, "") == 0) { AppIdInfo *info = g_hash_table_lookup (app_ids, name); if (info != NULL) { info->exited = TRUE; if (info->pending == NULL) g_hash_table_remove (app_ids, name); } } } void xdp_connection_track_name_owners (GDBusConnection *connection) { g_dbus_connection_signal_subscribe (connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameOwnerChanged", "/org/freedesktop/DBus", NULL, G_DBUS_SIGNAL_FLAGS_NONE, name_owner_changed, NULL, NULL); }