mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
src: use helpers and add group_fd to remote API
This commit is contained in:
@ -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");
|
||||
"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,
|
||||
|
||||
@ -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()
|
||||
|
||||
Reference in New Issue
Block a user