mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
build: drop legacy v2 service and simplify build system
This removes -Dagent and just uses -Dtools as it only affects sysprof-cli and sysprof-agent. We still need to patch sysprof-cli for recent changes as we did for sysprof-agent though. Additionally, we haven't used the v2 service in forever, so drop that as I can't imagine anyone has been using it.
This commit is contained in:
556
src/sysprofd/helpers.c
Normal file
556
src/sysprofd/helpers.c
Normal file
@ -0,0 +1,556 @@
|
||||
/* 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 "helpers"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <gio/gio.h>
|
||||
#include <errno.h>
|
||||
#ifdef __linux__
|
||||
# include <linux/perf_event.h>
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef __linux__
|
||||
static gboolean
|
||||
linux_list_processes (gint32 **processes,
|
||||
gsize *n_processes)
|
||||
{
|
||||
g_autoptr(GDir) dir = NULL;
|
||||
g_autoptr(GArray) pids = NULL;
|
||||
const gchar *name;
|
||||
|
||||
if (!(dir = g_dir_open ("/proc/", 0, NULL)))
|
||||
return FALSE;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*n_processes = pids->len;
|
||||
*processes = (gint32 *)(gpointer)g_array_free (g_steal_pointer (&pids), FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
helpers_list_processes (gint32 **processes,
|
||||
gsize *n_processes)
|
||||
{
|
||||
g_return_val_if_fail (processes != NULL, FALSE);
|
||||
g_return_val_if_fail (n_processes != NULL, FALSE);
|
||||
|
||||
*processes = NULL;
|
||||
*n_processes = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
return linux_list_processes (processes, n_processes);
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
helpers_perf_event_open (GVariant *options,
|
||||
gint32 pid,
|
||||
gint32 cpu,
|
||||
gint group_fd,
|
||||
guint64 flags,
|
||||
gint *out_fd)
|
||||
{
|
||||
#ifndef __linux__
|
||||
*out_fd = -1;
|
||||
return FALSE;
|
||||
#else
|
||||
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 use_clockid = 0;
|
||||
gint sample_id_all = 0;
|
||||
|
||||
g_assert (out_fd != NULL);
|
||||
|
||||
*out_fd = -1;
|
||||
|
||||
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:
|
||||
errno = EINVAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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;
|
||||
else
|
||||
attr.clockid = clockid;
|
||||
attr.use_clockid = use_clockid;
|
||||
#endif
|
||||
|
||||
attr.size = sizeof attr;
|
||||
|
||||
errno = 0;
|
||||
*out_fd = _perf_event_open (&attr, pid, cpu, group_fd, flags);
|
||||
return *out_fd >= 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
helpers_get_proc_file (const gchar *path,
|
||||
gchar **contents,
|
||||
gsize *len)
|
||||
{
|
||||
g_autofree gchar *canon = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
|
||||
g_assert (path != NULL);
|
||||
g_assert (contents != NULL);
|
||||
g_assert (len != NULL);
|
||||
|
||||
*contents = NULL;
|
||||
*len = 0;
|
||||
|
||||
/* Canonicalize filename */
|
||||
file = g_file_new_for_path (path);
|
||||
canon = g_file_get_path (file);
|
||||
|
||||
return g_file_is_native (file) &&
|
||||
(g_str_has_prefix (canon, "/proc/") || g_str_has_prefix (canon, "/sys/")) &&
|
||||
g_file_get_contents (canon, contents, len, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
helpers_get_proc_fd (const gchar *path,
|
||||
gint *out_fd)
|
||||
{
|
||||
g_autofree gchar *canon = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
|
||||
g_assert (path != NULL);
|
||||
g_assert (out_fd != NULL);
|
||||
|
||||
/* Canonicalize filename */
|
||||
file = g_file_new_for_path (path);
|
||||
canon = g_file_get_path (file);
|
||||
|
||||
return g_file_is_native (file) &&
|
||||
(g_str_has_prefix (canon, "/proc/") || g_str_has_prefix (canon, "/sys/")) &&
|
||||
-1 != (*out_fd = open (canon, O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
gboolean
|
||||
helpers_can_see_pids (void)
|
||||
{
|
||||
g_autofree gchar *contents = NULL;
|
||||
gsize len = 0;
|
||||
|
||||
if (g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS))
|
||||
return FALSE;
|
||||
|
||||
if (helpers_get_proc_file ("/proc/mounts", &contents, &len))
|
||||
{
|
||||
g_auto(GStrv) lines = g_strsplit (contents, "\n", 0);
|
||||
|
||||
for (guint i = 0; lines[i]; i++)
|
||||
{
|
||||
if (!g_str_has_prefix (lines[i], "proc /proc "))
|
||||
continue;
|
||||
|
||||
if (strstr (lines[i], "hidepid=") && !strstr (lines[i], "hidepid=0"))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
helpers_list_processes_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_autofree gint32 *processes = NULL;
|
||||
gsize n_processes;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (helpers_list_processes (&processes, &n_processes))
|
||||
{
|
||||
GArray *ar;
|
||||
|
||||
ar = g_array_new (FALSE, FALSE, sizeof (gint32));
|
||||
g_array_append_vals (ar, processes, n_processes);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&ar),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_new_error (task,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Failed to list processes");
|
||||
}
|
||||
|
||||
void
|
||||
helpers_list_processes_async (GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, helpers_list_processes_async);
|
||||
g_task_run_in_thread (task, helpers_list_processes_worker);
|
||||
}
|
||||
|
||||
gboolean
|
||||
helpers_list_processes_finish (GAsyncResult *result,
|
||||
gint32 **processes,
|
||||
gsize *n_processes,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) ret = NULL;
|
||||
|
||||
g_return_val_if_fail (G_IS_TASK (result), FALSE);
|
||||
|
||||
if ((ret = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
if (n_processes)
|
||||
*n_processes = ret->len;
|
||||
|
||||
if (processes)
|
||||
*processes = (gint32 *)(gpointer)g_array_free (ret, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (processes)
|
||||
*processes = NULL;
|
||||
if (n_processes)
|
||||
*n_processes = 0;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
needs_escape (const gchar *str)
|
||||
{
|
||||
for (; *str; str++)
|
||||
{
|
||||
if (g_ascii_isspace (*str) || *str == '\'' || *str == '"')
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
postprocess_cmdline (gchar **str,
|
||||
gsize len)
|
||||
{
|
||||
g_autoptr(GPtrArray) parts = g_ptr_array_new_with_free_func (g_free);
|
||||
g_autofree gchar *instr = NULL;
|
||||
const gchar *begin = NULL;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
instr = *str;
|
||||
|
||||
for (gsize i = 0; i < len; i++)
|
||||
{
|
||||
if (!begin && instr[i])
|
||||
{
|
||||
begin = &instr[i];
|
||||
}
|
||||
else if (begin && instr[i] == '\0')
|
||||
{
|
||||
if (needs_escape (begin))
|
||||
g_ptr_array_add (parts, g_shell_quote (begin));
|
||||
else
|
||||
g_ptr_array_add (parts, g_strdup (begin));
|
||||
|
||||
begin = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the last byte was not \0, as can happen with prctl(), then we need
|
||||
* to add it here manually.
|
||||
*/
|
||||
if (begin)
|
||||
{
|
||||
if (needs_escape (begin))
|
||||
g_ptr_array_add (parts, g_shell_quote (begin));
|
||||
else
|
||||
g_ptr_array_add (parts, g_strdup (begin));
|
||||
}
|
||||
|
||||
g_ptr_array_add (parts, NULL);
|
||||
|
||||
*str = g_strjoinv (" ", (gchar **)parts->pdata);
|
||||
}
|
||||
|
||||
static void
|
||||
postprocess_rstrip (gchar **str,
|
||||
gsize len)
|
||||
{
|
||||
g_strchomp (*str);
|
||||
}
|
||||
|
||||
static void
|
||||
add_pid_proc_file_to (gint pid,
|
||||
const gchar *name,
|
||||
GVariantDict *dict,
|
||||
void (*postprocess) (gchar **, gsize))
|
||||
{
|
||||
g_autofree gchar *path = NULL;
|
||||
g_autofree gchar *contents = NULL;
|
||||
gsize len;
|
||||
|
||||
g_assert (pid > -1);
|
||||
g_assert (name != NULL);
|
||||
g_assert (dict != NULL);
|
||||
|
||||
path = g_strdup_printf ("/proc/%d/%s", pid, name);
|
||||
|
||||
if (g_file_get_contents (path, &contents, &len, NULL))
|
||||
{
|
||||
if (postprocess)
|
||||
postprocess (&contents, len);
|
||||
g_variant_dict_insert (dict, name, "s", contents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GVariant *
|
||||
helpers_get_process_info (const gchar *attributes)
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
g_autofree gint *processes = NULL;
|
||||
gsize n_processes = 0;
|
||||
gboolean want_statm;
|
||||
gboolean want_cmdline;
|
||||
gboolean want_comm;
|
||||
gboolean want_maps;
|
||||
gboolean want_mountinfo;
|
||||
gboolean want_cgroup;
|
||||
|
||||
if (attributes == NULL)
|
||||
attributes = "";
|
||||
|
||||
want_statm = !!strstr (attributes, "statm");
|
||||
want_cmdline = !!strstr (attributes, "cmdline");
|
||||
want_maps = !!strstr (attributes, "maps");
|
||||
want_mountinfo = !!strstr (attributes, "mountinfo");
|
||||
want_comm = !!strstr (attributes, "comm");
|
||||
want_cgroup = !!strstr (attributes, "cgroup");
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
|
||||
|
||||
if (helpers_list_processes (&processes, &n_processes))
|
||||
{
|
||||
for (guint i = 0; i < n_processes; i++)
|
||||
{
|
||||
gint pid = processes[i];
|
||||
GVariantDict dict;
|
||||
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
g_variant_dict_insert (&dict, "pid", "i", pid, NULL);
|
||||
|
||||
if (want_statm)
|
||||
add_pid_proc_file_to (pid, "statm", &dict, postprocess_rstrip);
|
||||
|
||||
if (want_cmdline)
|
||||
add_pid_proc_file_to (pid, "cmdline", &dict, postprocess_cmdline);
|
||||
|
||||
if (want_comm)
|
||||
add_pid_proc_file_to (pid, "comm", &dict, postprocess_rstrip);
|
||||
|
||||
if (want_maps)
|
||||
add_pid_proc_file_to (pid, "maps", &dict, postprocess_rstrip);
|
||||
|
||||
if (want_mountinfo)
|
||||
add_pid_proc_file_to (pid, "mountinfo", &dict, postprocess_rstrip);
|
||||
|
||||
if (want_cgroup)
|
||||
add_pid_proc_file_to (pid, "cgroup", &dict, postprocess_rstrip);
|
||||
|
||||
g_variant_builder_add_value (&builder, g_variant_dict_end (&dict));
|
||||
}
|
||||
}
|
||||
|
||||
return g_variant_take_ref (g_variant_builder_end (&builder));
|
||||
}
|
||||
53
src/sysprofd/helpers.h
Normal file
53
src/sysprofd/helpers.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* 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
|
||||
|
||||
gboolean helpers_can_see_pids (void);
|
||||
gboolean helpers_list_processes (gint32 **processes,
|
||||
gsize *n_processes);
|
||||
void helpers_list_processes_async (GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean helpers_list_processes_finish (GAsyncResult *result,
|
||||
gint32 **processes,
|
||||
gsize *n_processes,
|
||||
GError **error);
|
||||
gboolean helpers_perf_event_open (GVariant *options,
|
||||
gint32 pid,
|
||||
gint32 cpu,
|
||||
gint group_fd,
|
||||
guint64 flags,
|
||||
gint *out_fd);
|
||||
gboolean helpers_get_proc_file (const gchar *path,
|
||||
gchar **contents,
|
||||
gsize *len);
|
||||
gboolean helpers_get_proc_fd (const gchar *path,
|
||||
gint *out_fd);
|
||||
GVariant *helpers_get_process_info (const gchar *attributes);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,218 +0,0 @@
|
||||
/* ipc-legacy-impl.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 "ipc-legacy-impl"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
#include <polkit/polkit.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../libsysprof/sysprof-kallsyms.h"
|
||||
#include "helpers.h"
|
||||
#include "ipc-legacy-impl.h"
|
||||
|
||||
struct _IpcLegacyImpl
|
||||
{
|
||||
IpcLegacySysprof2Skeleton parent;
|
||||
};
|
||||
|
||||
enum {
|
||||
ACTIVITY,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals [N_SIGNALS];
|
||||
|
||||
static gboolean
|
||||
ipc_legacy_impl_handle_perf_event_open (IpcLegacySysprof2 *service,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *options,
|
||||
gint32 pid,
|
||||
gint32 cpu,
|
||||
guint64 flags)
|
||||
{
|
||||
gint out_fd = -1;
|
||||
gint handle;
|
||||
|
||||
g_assert (IPC_IS_LEGACY_IMPL (service));
|
||||
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
|
||||
g_message ("LEGACY: PerfEventOpen(pid=%d, cpu=%d)", pid, cpu);
|
||||
|
||||
errno = 0;
|
||||
if (!helpers_perf_event_open (options, pid, cpu, -1, flags, &out_fd))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (g_steal_pointer (&invocation),
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Failed to create perf counter: %s",
|
||||
g_strerror (errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
{
|
||||
ipc_legacy_sysprof2_complete_perf_event_open (service,
|
||||
g_steal_pointer (&invocation),
|
||||
out_fd_list,
|
||||
g_variant_new ("h", handle));
|
||||
}
|
||||
}
|
||||
|
||||
if (out_fd != -1)
|
||||
close (out_fd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ipc_legacy_impl_handle_get_kernal_symbols (IpcLegacySysprof2 *service,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_autoptr(SysprofKallsyms) kallsyms = NULL;
|
||||
GVariantBuilder builder;
|
||||
const gchar *name;
|
||||
guint64 addr;
|
||||
guint8 type;
|
||||
|
||||
g_assert (IPC_IS_LEGACY_IMPL (service));
|
||||
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
|
||||
g_message ("LEGACY: GetKernelSymbols()");
|
||||
|
||||
if (!(kallsyms = sysprof_kallsyms_new ("/proc/kallsyms")))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (g_steal_pointer (&invocation),
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Failed to create parse kallsyms");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(tys)"));
|
||||
while (sysprof_kallsyms_next (kallsyms, &name, &addr, &type))
|
||||
g_variant_builder_add (&builder, "(tys)", addr, type, name);
|
||||
|
||||
ipc_legacy_sysprof2_complete_get_kernel_symbols (service,
|
||||
g_steal_pointer (&invocation),
|
||||
g_variant_builder_end (&builder));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ipc_legacy_impl_g_authorize_method (GDBusInterfaceSkeleton *skeleton,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
PolkitAuthorizationResult *res = NULL;
|
||||
PolkitAuthority *authority = NULL;
|
||||
PolkitSubject *subject = NULL;
|
||||
const gchar *peer_name;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_assert (IPC_IS_LEGACY_IMPL (skeleton));
|
||||
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
|
||||
g_signal_emit (skeleton, signals [ACTIVITY], 0);
|
||||
|
||||
peer_name = g_dbus_method_invocation_get_sender (invocation);
|
||||
|
||||
if (!(authority = polkit_authority_get_sync (NULL, NULL)) ||
|
||||
!(subject = polkit_system_bus_name_new (peer_name)) ||
|
||||
!(res = polkit_authority_check_authorization_sync (authority,
|
||||
POLKIT_SUBJECT (subject),
|
||||
"org.gnome.sysprof3.profile",
|
||||
NULL,
|
||||
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
|
||||
NULL,
|
||||
NULL)) ||
|
||||
!polkit_authorization_result_get_is_authorized (res))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (g_steal_pointer (&invocation),
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Not authorized to make request");
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
g_clear_object (&authority);
|
||||
g_clear_object (&subject);
|
||||
g_clear_object (&res);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof2_iface_init (IpcLegacySysprof2Iface *iface)
|
||||
{
|
||||
iface->handle_perf_event_open = ipc_legacy_impl_handle_perf_event_open;
|
||||
iface->handle_get_kernel_symbols = ipc_legacy_impl_handle_get_kernal_symbols;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (IpcLegacyImpl, ipc_legacy_impl, IPC_LEGACY_TYPE_SYSPROF2_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (IPC_LEGACY_TYPE_SYSPROF2, sysprof2_iface_init))
|
||||
|
||||
static void
|
||||
ipc_legacy_impl_class_init (IpcLegacyImplClass *klass)
|
||||
{
|
||||
GDBusInterfaceSkeletonClass *skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
|
||||
|
||||
skeleton_class->g_authorize_method = ipc_legacy_impl_g_authorize_method;
|
||||
|
||||
signals [ACTIVITY] =
|
||||
g_signal_new ("activity",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ipc_legacy_impl_init (IpcLegacyImpl *self)
|
||||
{
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (self),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
}
|
||||
|
||||
IpcLegacySysprof2 *
|
||||
ipc_legacy_impl_new (void)
|
||||
{
|
||||
return g_object_new (IPC_TYPE_LEGACY_IMPL, NULL);
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* ipc-legacy-impl.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 "ipc-legacy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define IPC_TYPE_LEGACY_IMPL (ipc_legacy_impl_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (IpcLegacyImpl, ipc_legacy_impl, IPC, LEGACY_IMPL, IpcLegacySysprof2Skeleton)
|
||||
|
||||
IpcLegacySysprof2 *ipc_legacy_impl_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,12 +1,21 @@
|
||||
ipc_profiler_src = gnome.gdbus_codegen('ipc-profiler',
|
||||
sources: '../org.gnome.Sysprof3.Profiler.xml',
|
||||
interface_prefix: 'org.gnome.Sysprof3.',
|
||||
namespace: 'Ipc',
|
||||
)
|
||||
|
||||
ipc_service_src = gnome.gdbus_codegen('ipc-service',
|
||||
sources: '../org.gnome.Sysprof3.Service.xml',
|
||||
interface_prefix: 'org.gnome.Sysprof3.',
|
||||
namespace: 'Ipc',
|
||||
)
|
||||
|
||||
sysprofd_sources = [
|
||||
'../libsysprof/sysprof-kallsyms.c',
|
||||
'sysprofd.c',
|
||||
'ipc-legacy-impl.c',
|
||||
'ipc-rapl-profiler.c',
|
||||
'ipc-service-impl.c',
|
||||
'sysprof-turbostat.c',
|
||||
helpers_sources,
|
||||
ipc_legacy_src,
|
||||
'helpers.c',
|
||||
ipc_profiler_src,
|
||||
ipc_service_src,
|
||||
]
|
||||
@ -26,7 +35,7 @@ sysprofd = executable('sysprofd', sysprofd_sources,
|
||||
install: true,
|
||||
install_dir: pkglibexecdir,
|
||||
pie: true,
|
||||
include_directories: [include_directories('.'), ipc_include_dirs],
|
||||
include_directories: [include_directories('.')],
|
||||
)
|
||||
|
||||
sysprofdconf = configuration_data()
|
||||
@ -69,28 +78,3 @@ i18n.merge_file(
|
||||
install: true,
|
||||
install_dir: join_paths(datadir, 'polkit-1/actions'),
|
||||
)
|
||||
|
||||
#
|
||||
# For org.gnome.Sysprof2 Compatibility
|
||||
#
|
||||
|
||||
configure_file(
|
||||
input: 'org.gnome.Sysprof2.service.in',
|
||||
output: 'org.gnome.Sysprof2.service',
|
||||
configuration: sysprofdconf,
|
||||
install_dir: join_paths(datadir, 'dbus-1/system-services'),
|
||||
)
|
||||
|
||||
configure_file(
|
||||
input: 'org.gnome.Sysprof2.conf.in',
|
||||
output: 'org.gnome.Sysprof2.conf',
|
||||
configuration: sysprofdconf,
|
||||
install_dir: join_paths(datadir, 'dbus-1/system.d'),
|
||||
)
|
||||
|
||||
configure_file(
|
||||
input: 'sysprof2.service.in',
|
||||
output: 'sysprof2.service',
|
||||
configuration: sysprofdconf,
|
||||
install_dir: systemdunitdir,
|
||||
)
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<!-- Only root can own the service -->
|
||||
<policy user="root">
|
||||
<allow own="org.gnome.Sysprof2"/>
|
||||
<allow send_destination="org.gnome.Sysprof2"/>
|
||||
<allow receive_sender="org.gnome.Sysprof2"/>
|
||||
</policy>
|
||||
|
||||
<!-- Anyone can send messages to the owner of org.gnome.Sysprof2 -->
|
||||
<policy context="default">
|
||||
<allow send_destination="org.gnome.Sysprof2"/>
|
||||
<allow receive_sender="org.gnome.Sysprof2"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
@ -1,5 +0,0 @@
|
||||
[D-BUS Service]
|
||||
Name=org.gnome.Sysprof2
|
||||
Exec=@sysprofdprivdir@/sysprofd
|
||||
User=root
|
||||
SystemdService=sysprof2.service
|
||||
@ -1,8 +0,0 @@
|
||||
[Unit]
|
||||
Description=Sysprof Daemon
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=org.gnome.Sysprof2
|
||||
ExecStart=@sysprofdprivdir@/sysprofd
|
||||
|
||||
@ -26,10 +26,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "ipc-legacy.h"
|
||||
#include "ipc-service.h"
|
||||
|
||||
#include "ipc-legacy-impl.h"
|
||||
#include "ipc-rapl-profiler.h"
|
||||
#include "ipc-service-impl.h"
|
||||
|
||||
@ -127,18 +125,15 @@ main (gint argc,
|
||||
|
||||
if ((bus = g_bus_get_sync (bus_type, NULL, &error)))
|
||||
{
|
||||
g_autoptr(IpcLegacySysprof2) v2_service = ipc_legacy_impl_new ();
|
||||
g_autoptr(IpcProfiler) rapl = ipc_rapl_profiler_new ();
|
||||
g_autoptr(IpcService) v3_service = ipc_service_impl_new ();
|
||||
|
||||
g_signal_connect (v3_service, "activity", G_CALLBACK (activity_cb), NULL);
|
||||
g_signal_connect (v2_service, "activity", G_CALLBACK (activity_cb), NULL);
|
||||
g_signal_connect (rapl, "activity", G_CALLBACK (activity_cb), NULL);
|
||||
|
||||
activity_cb (NULL, NULL);
|
||||
|
||||
if (g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (v3_service), bus, V3_PATH, &error) &&
|
||||
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (v2_service), bus, V2_PATH, &error) &&
|
||||
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (rapl), bus, RAPL_PATH, &error))
|
||||
{
|
||||
for (guint i = 0; i < G_N_ELEMENTS (bus_names); i++)
|
||||
|
||||
Reference in New Issue
Block a user