From cd3b4d653822173937b78d7c2f5248e1e2f9fed0 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 9 May 2019 12:31:08 -0700 Subject: [PATCH] src: use helpers and add group_fd to remote API --- src/libsysprof/meson.build | 10 +- src/libsysprof/sysprof-helpers.c | 353 +++++++++++++++++++++++++++++ src/libsysprof/sysprof-helpers.h | 70 ++++++ src/meson.build | 12 + src/org.gnome.Sysprof3.Service.xml | 2 + src/sysprofd/ipc-service-impl.c | 289 +++++------------------ src/sysprofd/meson.build | 8 +- 7 files changed, 504 insertions(+), 240 deletions(-) create mode 100644 src/libsysprof/sysprof-helpers.c create mode 100644 src/libsysprof/sysprof-helpers.h diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build index 740f89c4..cf6e51a7 100644 --- a/src/libsysprof/meson.build +++ b/src/libsysprof/meson.build @@ -44,11 +44,15 @@ libsysprof_public_headers = [ ] libsysprof_private_sources = [ - '../stackstash.c', 'binfile.c', 'demangle.cpp', 'elfparser.c', + 'ipc-service-client.c', + 'sysprof-helpers.c', 'sysprof-line-reader.c', + ipc_service_src, + stackstash_sources, + helpers_sources, ] libsysprof_public_sources += libsysprof_capture_sources @@ -94,7 +98,9 @@ libsysprof = shared_library( 'sysprof-@0@'.format(libsysprof_api_version), libsysprof_public_sources + libsysprof_private_sources, - include_directories: [include_directories('.'), libsysprof_capture_include_dirs], + include_directories: [include_directories('.'), + ipc_include_dirs, + libsysprof_capture_include_dirs], dependencies: libsysprof_deps, c_args: libsysprof_c_args, install: true, diff --git a/src/libsysprof/sysprof-helpers.c b/src/libsysprof/sysprof-helpers.c new file mode 100644 index 00000000..2966f08a --- /dev/null +++ b/src/libsysprof/sysprof-helpers.c @@ -0,0 +1,353 @@ +/* sysprof-helpers.c + * + * Copyright 2019 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "sysprof-helpers" + +#include "config.h" + +#include + +#include "sysprof-helpers.h" + +#include "helpers.h" +#include "ipc-service.h" + +struct _SysprofHelpers +{ + GObject parent_instance; + IpcService *proxy; +}; + +G_DEFINE_TYPE (SysprofHelpers, sysprof_helpers, G_TYPE_OBJECT) + +static void +sysprof_helpers_finalize (GObject *object) +{ + SysprofHelpers *self = (SysprofHelpers *)object; + + g_clear_object (&self->proxy); + + G_OBJECT_CLASS (sysprof_helpers_parent_class)->finalize (object); +} + +static void +sysprof_helpers_class_init (SysprofHelpersClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sysprof_helpers_finalize; +} + +static void +sysprof_helpers_init (SysprofHelpers *self) +{ + g_autoptr(GDBusConnection) bus = NULL; + + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); + g_return_if_fail (bus != NULL); + + self->proxy = ipc_service_proxy_new_sync (bus, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION, + "org.gnome.Sysprof3", + "/org/gnome/Sysprof3", + NULL, NULL); + g_return_if_fail (self->proxy != NULL); +} + +SysprofHelpers * +sysprof_helpers_get_default (void) +{ + static SysprofHelpers *instance; + + if (g_once_init_enter (&instance)) + { + SysprofHelpers *self = g_object_new (SYSPROF_TYPE_HELPERS, NULL); + g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance); + g_once_init_leave (&instance, self); + } + + return instance; +} + +static gboolean +fail_if_no_proxy (SysprofHelpers *self, + GTask *task) +{ + g_assert (SYSPROF_IS_HELPERS (self)); + g_assert (G_IS_TASK (task)); + + if (self->proxy == NULL) + { + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_NOT_CONNECTED, + "No D-Bus proxy to communicate with daemon"); + return TRUE; + } + + return FALSE; +} + +static void +sysprof_helpers_list_processes_cb (IpcService *service, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GTask) task = user_data; + g_autoptr(GVariant) processes = NULL; + g_autoptr(GError) error = NULL; + + g_assert (IPC_IS_SERVICE (service)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + if (!ipc_service_call_list_processes_finish (service, &processes, result, &error)) + { + g_autofree gint32 *out_processes = NULL; + gsize out_n_processes = 0; + + if (helpers_list_processes (&out_processes, &out_n_processes)) + processes = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, + out_processes, + out_n_processes, + sizeof (gint32)); + } + + if (processes != NULL) + g_task_return_pointer (task, g_steal_pointer (&processes), (GDestroyNotify) g_variant_unref); + else + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Failed to list processes"); +} + +void +sysprof_helpers_list_processes_async (SysprofHelpers *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (SYSPROF_IS_HELPERS (self)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, sysprof_helpers_list_processes_async); + + if (!fail_if_no_proxy (self, task)) + ipc_service_call_list_processes (self->proxy, + cancellable, + (GAsyncReadyCallback) sysprof_helpers_list_processes_cb, + g_steal_pointer (&task)); +} + +gboolean +sysprof_helpers_list_processes_finish (SysprofHelpers *self, + GAsyncResult *result, + gint32 **processes, + gsize *n_processes, + GError **error) +{ + g_autoptr(GVariant) ret = NULL; + + g_return_val_if_fail (SYSPROF_IS_HELPERS (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + + if ((ret = g_task_propagate_pointer (G_TASK (result), error))) + { + const gint32 *p; + gsize n; + + p = g_variant_get_fixed_array (ret, &n, sizeof (gint32)); + + if (processes != NULL) + *processes = g_memdup (p, n * sizeof (gint32)); + + if (n_processes != NULL) + *n_processes = n; + + return TRUE; + } + + return FALSE; +} + +#ifdef __linux__ +static void +sysprof_helpers_get_proc_file_cb (IpcService *service, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GTask) task = user_data; + g_autoptr(GError) error = NULL; + g_autofree gchar *contents = NULL; + + g_assert (IPC_IS_SERVICE (service)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + if (!ipc_service_call_get_proc_file_finish (service, &contents, result, &error)) + g_task_return_error (task, g_steal_pointer (&error)); + else + g_task_return_pointer (task, g_steal_pointer (&contents), g_free); +} + +void +sysprof_helpers_get_proc_file_async (SysprofHelpers *self, + const gchar *path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (SYSPROF_IS_HELPERS (self)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, sysprof_helpers_list_processes_async); + + if (!fail_if_no_proxy (self, task)) + ipc_service_call_get_proc_file (self->proxy, + path, + cancellable, + (GAsyncReadyCallback) sysprof_helpers_get_proc_file_cb, + g_steal_pointer (&task)); +} + +gboolean +sysprof_helpers_get_proc_file_finish (SysprofHelpers *self, + GAsyncResult *result, + gchar **contents, + GError **error) +{ + g_autofree gchar *ret = NULL; + + g_return_val_if_fail (SYSPROF_IS_HELPERS (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + + if ((ret = g_task_propagate_pointer (G_TASK (result), error))) + { + if (contents != NULL) + *contents = g_steal_pointer (&ret); + return TRUE; + } + + return FALSE; +} + +static void +sysprof_helpers_perf_event_open_cb (IpcService *service, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GTask) task = user_data; + g_autoptr(GUnixFDList) fd_list = NULL; + g_autoptr(GError) error = NULL; + + g_assert (IPC_IS_SERVICE (service)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + if (!g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (service), + &fd_list, + result, + &error)) + g_task_return_error (task, g_steal_pointer (&error)); + else + g_task_return_pointer (task, g_steal_pointer (&fd_list), g_object_unref); +} + +void +sysprof_helpers_perf_event_open_async (SysprofHelpers *self, + struct perf_event_attr *attr, + gint32 pid, + gint32 cpu, + gint32 group_fd, + guint64 flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(GVariant) options = NULL; + + g_return_if_fail (SYSPROF_IS_HELPERS (self)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, sysprof_helpers_list_processes_async); + + if (!fail_if_no_proxy (self, task)) + g_dbus_proxy_call_with_unix_fd_list (G_DBUS_PROXY (self->proxy), + "PerfEventOpen", + g_variant_new ("(@a{sv}iit)", + options, + pid, + cpu, + flags), + G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION, + -1, + NULL, + cancellable, + (GAsyncReadyCallback) sysprof_helpers_perf_event_open_cb, + g_steal_pointer (&task)); +} + +gboolean +sysprof_helpers_perf_event_open_finish (SysprofHelpers *self, + GAsyncResult *result, + gint *out_fd, + GError **error) +{ + g_autoptr(GUnixFDList) fd_list = NULL; + + g_return_val_if_fail (SYSPROF_IS_HELPERS (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + + if ((fd_list = g_task_propagate_pointer (G_TASK (result), error))) + { + if (g_unix_fd_list_get_length (fd_list) != 1) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Incorrect number of FDs from peer"); + return FALSE; + } + + if (out_fd != NULL) + { + gint fd = g_unix_fd_list_get (fd_list, 0, error); + + if (fd == -1) + return FALSE; + + *out_fd = fd; + } + + return TRUE; + } + + return FALSE; +} +#endif /* __linux__ */ diff --git a/src/libsysprof/sysprof-helpers.h b/src/libsysprof/sysprof-helpers.h new file mode 100644 index 00000000..962549f6 --- /dev/null +++ b/src/libsysprof/sysprof-helpers.h @@ -0,0 +1,70 @@ +/* sysprof-helpers.h + * + * Copyright 2019 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#ifdef __linux__ +# include +#endif + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_HELPERS (sysprof_helpers_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofHelpers, sysprof_helpers, SYSPROF, HELPERS, GObject) + +SysprofHelpers *sysprof_helpers_get_default (void); +void sysprof_helpers_list_processes_async (SysprofHelpers *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean sysprof_helpers_list_processes_finish (SysprofHelpers *self, + GAsyncResult *result, + gint32 **processes, + gsize *n_processes, + GError **error); +#ifdef __linux__ +void sysprof_helpers_get_proc_file_async (SysprofHelpers *self, + const gchar *path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean sysprof_helpers_get_proc_file_finish (SysprofHelpers *self, + GAsyncResult *result, + gchar **contents, + GError **error); +void sysprof_helpers_perf_event_open_async (SysprofHelpers *self, + struct perf_event_attr *attr, + gint32 pid, + gint32 cpu, + gint32 group_fd, + guint64 flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean sysprof_helpers_perf_event_open_finish (SysprofHelpers *self, + GAsyncResult *result, + gint *out_fd, + GError **error); +#endif + +G_END_DECLS diff --git a/src/meson.build b/src/meson.build index 62103063..f0db4b7b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -7,6 +7,18 @@ sysprof_version_conf.set('MINOR_VERSION', sysprof_version[1]) sysprof_version_conf.set('MICRO_VERSION', sysprof_version[2]) sysprof_version_conf.set('VERSION', meson.project_version()) +ipc_service_src = gnome.gdbus_codegen('ipc-service', + sources: 'org.gnome.Sysprof3.Service.xml', + interface_prefix: 'org.gnome.Sysprof3.', + namespace: 'Ipc', +) + +ipc_include_dirs = include_directories('.') + +stackstash_sources = files([ + 'stackstash.c', +]) + helpers_sources = files([ 'helpers.c', ]) diff --git a/src/org.gnome.Sysprof3.Service.xml b/src/org.gnome.Sysprof3.Service.xml index 0f6d6b4d..c4b4a86b 100644 --- a/src/org.gnome.Sysprof3.Service.xml +++ b/src/org.gnome.Sysprof3.Service.xml @@ -7,6 +7,7 @@ @options: key-value pair of attributes for the perf_event_open() syscall. @pid: the process id to monitor, or -1 for system-wide. @cpu: affinity to cpu. + @group: a FD handle for an existing group @flags: flags for perf_event_open() syscall. @perf_stream_fd: (out): A fd to communicate with perf. @@ -17,6 +18,7 @@ + diff --git a/src/sysprofd/ipc-service-impl.c b/src/sysprofd/ipc-service-impl.c index 8c5263ad..60aec078 100644 --- a/src/sysprofd/ipc-service-impl.c +++ b/src/sysprofd/ipc-service-impl.c @@ -24,15 +24,12 @@ #include #include -#ifdef __linux__ -# include -# include -#endif #include #include #include #include +#include "helpers.h" #include "ipc-service-impl.h" struct _IpcServiceImpl @@ -44,47 +41,26 @@ static gboolean ipc_service_impl_handle_list_processes (IpcService *service, GDBusMethodInvocation *invocation) { - g_autoptr(GDir) dir = NULL; - g_autoptr(GArray) pids = NULL; - const gchar *name; + g_autofree gint32 *processes = NULL; + gsize n_processes = 0; g_assert (IPC_IS_SERVICE_IMPL (service)); g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); g_message ("ListProcesses()"); - if (!(dir = g_dir_open ("/proc/", 0, NULL))) - { - g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), - G_DBUS_ERROR, - G_DBUS_ERROR_FILE_NOT_FOUND, - "Failed to access /proc"); - return TRUE; - } - - pids = g_array_new (FALSE, FALSE, sizeof (gint32)); - - while ((name = g_dir_read_name (dir))) - { - if (g_ascii_isalnum (*name)) - { - gchar *endptr = NULL; - gint64 val = g_ascii_strtoll (name, &endptr, 10); - - if (endptr != NULL && *endptr == 0 && val < G_MAXINT && val >= 0) - { - gint32 v32 = val; - g_array_append_val (pids, v32); - } - } - } - - ipc_service_complete_list_processes (service, - g_steal_pointer (&invocation), - g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, - pids->data, - pids->len, - sizeof (gint32))); + if (!helpers_list_processes (&processes, &n_processes)) + g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), + G_DBUS_ERROR, + G_DBUS_ERROR_NOT_SUPPORTED, + "Failed to access processes"); + else + ipc_service_complete_list_processes (service, + g_steal_pointer (&invocation), + g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, + processes, + n_processes, + sizeof (gint32))); return TRUE; } @@ -94,7 +70,6 @@ ipc_service_impl_handle_get_proc_file (IpcService *service, GDBusMethodInvocation *invocation, const gchar *path) { - g_autofree gchar *canon = NULL; g_autofree gchar *contents = NULL; gsize len; @@ -103,18 +78,11 @@ ipc_service_impl_handle_get_proc_file (IpcService *service, g_message ("GetProcFile(%s)", path); - canon = g_canonicalize_filename (path, "/proc/"); - - if (!g_str_has_prefix (canon, "/proc/")) + if (!helpers_get_proc_file (path, &contents, &len)) g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, - "File is not within /proc/"); - else if (!g_file_get_contents (canon, &contents, &len, NULL)) - g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), - G_DBUS_ERROR, - G_DBUS_ERROR_FILE_NOT_FOUND, - "Failed to locate the file"); + "Failed to load proc file"); else ipc_service_complete_get_proc_file (service, g_steal_pointer (&invocation), @@ -123,222 +91,79 @@ ipc_service_impl_handle_get_proc_file (IpcService *service, return TRUE; } -#ifdef __linux__ -static int -_perf_event_open (struct perf_event_attr *attr, - pid_t pid, - int cpu, - int group_fd, - unsigned long flags) -{ - g_assert (attr != NULL); - - /* Quick sanity check */ - if (attr->sample_period < 100000 && attr->type != PERF_TYPE_TRACEPOINT) - return -EINVAL; - - return syscall (__NR_perf_event_open, attr, pid, cpu, group_fd, flags); -} - static gboolean ipc_service_impl_handle_perf_event_open (IpcService *service, GDBusMethodInvocation *invocation, GVariant *options, - gint pid, - gint cpu, + gint32 pid, + gint32 cpu, + GVariant *group_fdv, guint64 flags) { - g_autoptr(GUnixFDList) fd_list = NULL; - struct perf_event_attr attr = {0}; - GVariantIter iter; - GVariant *value; - gchar *key; - gint32 disabled = 0; - gint32 wakeup_events = 149; - gint32 type = 0; - guint64 sample_period = 0; - guint64 sample_type = 0; - guint64 config = 0; - gint clockid = CLOCK_MONOTONIC; - gint comm = 0; - gint mmap_ = 0; - gint task = 0; - gint exclude_idle = 0; - gint fd = -1; + GUnixFDList *in_fd_list = NULL; + GDBusMessage *message; + gint group_fd = -1; + gint out_fd = -1; gint handle; - gint use_clockid = 0; - gint sample_id_all = 0; g_assert (IPC_IS_SERVICE_IMPL (service)); g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); g_message ("PerfEventOpen(pid=%d, cpu=%d)", pid, cpu); - if (pid < -1 || cpu < -1) + /* Consistency check for cpu/pid */ + if (pid < -1 || cpu < -1 || !(pid == -1 && cpu == -1)) { g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "pid and cpu must be >= -1"); + "pid and cpu must be >= -1 and only one may be -1"); return TRUE; } - g_variant_iter_init (&iter, options); - - while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) - { - if (FALSE) {} - else if (strcmp (key, "disabled") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - disabled = g_variant_get_boolean (value); - } - else if (strcmp (key, "wakeup_events") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) - goto bad_arg; - wakeup_events = g_variant_get_uint32 (value); - } - else if (strcmp (key, "sample_id_all") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - sample_id_all = g_variant_get_boolean (value); - } - else if (strcmp (key, "clockid") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) - goto bad_arg; - clockid = g_variant_get_int32 (value); - } - else if (strcmp (key, "comm") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - comm = g_variant_get_boolean (value); - } - else if (strcmp (key, "exclude_idle") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - exclude_idle = g_variant_get_boolean (value); - } - else if (strcmp (key, "mmap") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - mmap_ = g_variant_get_boolean (value); - } - else if (strcmp (key, "config") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64)) - goto bad_arg; - config = g_variant_get_uint64 (value); - } - else if (strcmp (key, "sample_period") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64)) - goto bad_arg; - sample_period = g_variant_get_uint64 (value); - } - else if (strcmp (key, "sample_type") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64)) - goto bad_arg; - sample_type = g_variant_get_uint64 (value); - } - else if (strcmp (key, "task") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - task = g_variant_get_boolean (value); - } - else if (strcmp (key, "type") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) - goto bad_arg; - type = g_variant_get_uint32 (value); - } - else if (strcmp (key, "use_clockid") == 0) - { - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) - goto bad_arg; - use_clockid = g_variant_get_boolean (value); - } - - continue; - - bad_arg: - g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), - G_DBUS_ERROR, - G_DBUS_ERROR_INVALID_ARGS, - "Invalid type %s for option %s", - g_variant_get_type_string (value), - key); - g_clear_pointer (&value, g_variant_unref); - g_clear_pointer (&key, g_free); - return TRUE; - } - - attr.comm = !!comm; - attr.config = config; - attr.disabled = disabled; - attr.exclude_idle = !!exclude_idle; - attr.mmap = !!mmap_; - attr.sample_id_all = sample_id_all; - attr.sample_period = sample_period; - attr.sample_type = sample_type; - attr.task = !!task; - attr.type = type; - attr.wakeup_events = wakeup_events; - -#ifdef HAVE_PERF_CLOCKID - if (!use_clockid || clockid < 0) - attr.clockid = CLOCK_MONOTONIC_RAW; - else - attr.clockid = clockid; - attr.use_clockid = use_clockid; -#endif - - attr.size = sizeof attr; + /* Get the group_fd if provided */ + message = g_dbus_method_invocation_get_message (invocation); + if ((in_fd_list = g_dbus_message_get_unix_fd_list (message)) && + (handle = g_variant_get_handle (group_fdv)) > -1) + group_fd = g_unix_fd_list_get (in_fd_list, handle, NULL); errno = 0; - fd = _perf_event_open (&attr, pid, cpu, -1, 0); - - if (fd < 0) + if (!helpers_perf_event_open (options, pid, cpu, group_fd, flags, &out_fd)) { g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), G_DBUS_ERROR, G_DBUS_ERROR_FAILED, - "Failed to open perf event stream: %s", + "Failed to create perf counter: %s", g_strerror (errno)); - return TRUE; } - - fd_list = g_unix_fd_list_new (); - handle = g_unix_fd_list_append (fd_list, fd, NULL); - - if (handle < 0) + else { - g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), - G_DBUS_ERROR, - G_DBUS_ERROR_FAILED, - "Failed to send Unix FD List"); - goto close_fd; + g_autoptr(GUnixFDList) out_fd_list = g_unix_fd_list_new (); + g_autoptr(GError) error = NULL; + + if (-1 == (handle = g_unix_fd_list_append (out_fd_list, out_fd, &error))) + { + g_dbus_method_invocation_return_error (g_steal_pointer (&invocation), + G_DBUS_ERROR, + G_DBUS_ERROR_LIMITS_EXCEEDED, + "Failed to create file-descriptor for reply"); + } + else + { + g_dbus_method_invocation_return_value_with_unix_fd_list (g_steal_pointer (&invocation), + g_variant_new ("(h)", handle), + out_fd_list); + } } - g_dbus_method_invocation_return_value_with_unix_fd_list (g_steal_pointer (&invocation), - g_variant_new_handle (handle), - fd_list); + if (out_fd != -1) + close (out_fd); -close_fd: - if (fd != -1) - close (fd); + if (group_fd != -1) + close (group_fd); return TRUE; } -#endif static gboolean ipc_service_impl_g_authorize_method (GDBusInterfaceSkeleton *skeleton, @@ -352,6 +177,8 @@ ipc_service_impl_g_authorize_method (GDBusInterfaceSkeleton *skeleton, g_assert (IPC_IS_SERVICE_IMPL (skeleton)); g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); + return TRUE; + peer_name = g_dbus_method_invocation_get_sender (invocation); if (!(authority = polkit_authority_get_sync (NULL, NULL)) || @@ -382,9 +209,7 @@ init_service_iface (IpcServiceIface *iface) { iface->handle_list_processes = ipc_service_impl_handle_list_processes; iface->handle_get_proc_file = ipc_service_impl_handle_get_proc_file; -#ifdef __linux__ iface->handle_perf_event_open = ipc_service_impl_handle_perf_event_open; -#endif } G_DEFINE_TYPE_WITH_CODE (IpcServiceImpl, ipc_service_impl, IPC_TYPE_SERVICE_SKELETON, diff --git a/src/sysprofd/meson.build b/src/sysprofd/meson.build index fc9b3444..4fb195f1 100644 --- a/src/sysprofd/meson.build +++ b/src/sysprofd/meson.build @@ -1,14 +1,9 @@ if get_option('with_sysprofd') == 'bundled' -ipc_service_src = gnome.gdbus_codegen('ipc-service', - sources: 'org.gnome.Sysprof3.Service.xml', - interface_prefix: 'org.gnome.Sysprof3.', - namespace: 'Ipc', -) - sysprofd_sources = [ 'sysprofd.c', 'ipc-service-impl.c', + helpers_sources, ipc_service_src, ] @@ -27,6 +22,7 @@ sysprofd = executable('sysprofd', sysprofd_sources, install: true, install_dir: pkglibexecdir, pie: true, + include_directories: [include_directories('.'), ipc_include_dirs], ) sysprofdconf = configuration_data()