[sysprof] src: use helpers and add group_fd to remote API



commit cd3b4d653822173937b78d7c2f5248e1e2f9fed0
Author: Christian Hergert <chergert redhat com>
Date:   Thu May 9 12:31:08 2019 -0700

    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(-)
---
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index 740f89c..cf6e51a 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 0000000..2966f08
--- /dev/null
+++ b/src/libsysprof/sysprof-helpers.c
@@ -0,0 +1,353 @@
+/* sysprof-helpers.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "sysprof-helpers"
+
+#include "config.h"
+
+#include <gio/gunixfdlist.h>
+
+#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 0000000..962549f
--- /dev/null
+++ b/src/libsysprof/sysprof-helpers.h
@@ -0,0 +1,70 @@
+/* sysprof-helpers.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+#ifdef __linux__
+# include <linux/perf_event.h>
+#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 6210306..f0db4b7 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 0f6d6b4..c4b4a86 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 @@
       <arg name="options" type="a{sv}" direction="in"/>
       <arg name="pid" type="i" direction="in"/>
       <arg name="cpu" type="i" direction="in"/>
+      <arg name="group_fd" type="h" direction="in"/>
       <arg name="flags" type="t" direction="in"/>
       <arg name="perf_stream_fd" type="h" direction="out"/>
     </method>
diff --git a/src/sysprofd/ipc-service-impl.c b/src/sysprofd/ipc-service-impl.c
index 8c5263a..60aec07 100644
--- a/src/sysprofd/ipc-service-impl.c
+++ b/src/sysprofd/ipc-service-impl.c
@@ -24,15 +24,12 @@
 
 #include <errno.h>
 #include <gio/gunixfdlist.h>
-#ifdef __linux__
-# include <linux/capability.h>
-# include <linux/perf_event.h>
-#endif
 #include <polkit/polkit.h>
 #include <sys/syscall.h>
 #include <time.h>
 #include <unistd.h>
 
+#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");
-      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);
+                                             "pid and cpu must be >= -1 and only one may be -1");
       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 fc9b344..4fb195f 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()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]