mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
Land Sysprof 2.x
This is a major redesign a modernization of Sysprof. The core data structures and design are largely the same, but it has been ported to Gtk3 and has lots of additions that should make your profiling experience smoother. Especially for those that are new to profiling. There are some very simple help docs added, but we really need the experts to come in and write some documentation here.
This commit is contained in:
14
daemon/Makefile.am
Normal file
14
daemon/Makefile.am
Normal file
@ -0,0 +1,14 @@
|
||||
if ENABLE_SYSPROFD
|
||||
|
||||
pkglibexec_PROGRAMS = sysprofd
|
||||
|
||||
sysprofd_SOURCES = \
|
||||
sysprofd.c \
|
||||
sd-bus-helper.c \
|
||||
sd-bus-helper.h
|
||||
|
||||
sysprofd_LDADD = $(SYSTEMD_LIBS)
|
||||
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
188
daemon/sd-bus-helper.c
Normal file
188
daemon/sd-bus-helper.c
Normal file
@ -0,0 +1,188 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sd-bus-helper.h"
|
||||
|
||||
/*
|
||||
* Various macros to simplify lifing code from sd-bus.
|
||||
*/
|
||||
#define assert_return(expr,val) do { if (!(expr)) return (val); } while (0)
|
||||
#define _cleanup_(f) __attribute__((cleanup(f)))
|
||||
#define STRV_FOREACH_PAIR(x, y, l) \
|
||||
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
|
||||
|
||||
/*
|
||||
* To support systemd 222, we need a couple helpers that were added
|
||||
* in 229. If we update code from systemd in the future, we can probably
|
||||
* drop these helpres.
|
||||
*/
|
||||
|
||||
static void
|
||||
_sd_bus_message_unrefp (sd_bus_message **m)
|
||||
{
|
||||
if (m && *m)
|
||||
{
|
||||
sd_bus_message_unref (*m);
|
||||
*m = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_sd_bus_creds_unrefp (sd_bus_creds **c)
|
||||
{
|
||||
if (c && *c)
|
||||
{
|
||||
sd_bus_creds_unref (*c);
|
||||
*c = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin verbatim code from systemd. Please try to keep this in sync until
|
||||
* systemd exposes helpers for polkit integration.
|
||||
*/
|
||||
static int
|
||||
check_good_user (sd_bus_message *m,
|
||||
uid_t good_user)
|
||||
{
|
||||
_cleanup_(_sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
uid_t sender_uid;
|
||||
int r;
|
||||
|
||||
assert (m);
|
||||
|
||||
if (good_user == UID_INVALID)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Don't trust augmented credentials for authorization */
|
||||
assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
|
||||
|
||||
r = sd_bus_creds_get_euid(creds, &sender_uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sender_uid == good_user;
|
||||
}
|
||||
|
||||
int
|
||||
bus_test_polkit (sd_bus_message *call,
|
||||
int capability,
|
||||
const char *action,
|
||||
const char **details,
|
||||
uid_t good_user,
|
||||
bool *_challenge,
|
||||
sd_bus_error *e)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert (call);
|
||||
assert (action);
|
||||
|
||||
/* Tests non-interactively! */
|
||||
|
||||
r = check_good_user(call, good_user);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_query_sender_privilege(call, capability);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r > 0)
|
||||
return 1;
|
||||
else {
|
||||
_cleanup_(_sd_bus_message_unrefp) sd_bus_message *request = NULL;
|
||||
_cleanup_(_sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
int authorized = false, challenge = false;
|
||||
const char *sender, **k, **v;
|
||||
|
||||
sender = sd_bus_message_get_sender(call);
|
||||
if (!sender)
|
||||
return -EBADMSG;
|
||||
|
||||
r = sd_bus_message_new_method_call(sd_bus_message_get_bus (call),
|
||||
&request,
|
||||
"org.freedesktop.PolicyKit1",
|
||||
"/org/freedesktop/PolicyKit1/Authority",
|
||||
"org.freedesktop.PolicyKit1.Authority",
|
||||
"CheckAuthorization");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(request,
|
||||
"(sa{sv})s",
|
||||
"system-bus-name", 1, "name", "s", sender,
|
||||
action);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(request, 'a', "{ss}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH_PAIR(k, v, details) {
|
||||
r = sd_bus_message_append(request, "{ss}", *k, *v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(request);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(request, "us", 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_call(sd_bus_message_get_bus(call), request, 0, e, &reply);
|
||||
if (r < 0) {
|
||||
/* Treat no PK available as access denied */
|
||||
if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
|
||||
sd_bus_error_free(e);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (authorized)
|
||||
return 1;
|
||||
|
||||
if (_challenge) {
|
||||
*_challenge = challenge;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EACCES;
|
||||
}
|
||||
36
daemon/sd-bus-helper.h
Normal file
36
daemon/sd-bus-helper.h
Normal file
@ -0,0 +1,36 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#ifndef SD_BUS_HELPER_H
|
||||
#define SD_BUS_HELPER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#define UID_INVALID ((uid_t)-1)
|
||||
|
||||
int bus_test_polkit (sd_bus_message *call,
|
||||
int capability,
|
||||
const char *action,
|
||||
const char **details,
|
||||
uid_t good_user,
|
||||
bool *_challenge,
|
||||
sd_bus_error *e);
|
||||
|
||||
#endif /* SD_BUS_HELPER_H */
|
||||
347
daemon/sysprofd.c
Normal file
347
daemon/sysprofd.c
Normal file
@ -0,0 +1,347 @@
|
||||
/* sysprofd.c
|
||||
*
|
||||
* Copyright (C) 2016 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus-helper.h"
|
||||
|
||||
#define BUS_TIMEOUT_USEC (1000000L * 10L)
|
||||
|
||||
static int
|
||||
_perf_event_open (struct perf_event_attr *attr,
|
||||
pid_t pid,
|
||||
int cpu,
|
||||
int group_fd,
|
||||
unsigned long flags)
|
||||
{
|
||||
assert (attr != NULL);
|
||||
|
||||
/* Quick sanity check */
|
||||
if (attr->sample_period < 100000)
|
||||
return -EINVAL;
|
||||
|
||||
return syscall (__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define GOTO(l) do { \
|
||||
fprintf (stderr, "GOTO: %s:%d: " #l "\n", __FUNCTION__, __LINE__); \
|
||||
goto l; \
|
||||
} while (0)
|
||||
#else
|
||||
#define GOTO(l) goto l
|
||||
#endif
|
||||
|
||||
static int
|
||||
sysprofd_perf_event_open (sd_bus_message *msg,
|
||||
void *user_data,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct perf_event_attr attr = { 0 };
|
||||
sd_bus_message *reply = NULL;
|
||||
sd_bus_message *kvpair;
|
||||
uint64_t flags = 0;
|
||||
int disabled = 0;
|
||||
int32_t wakeup_events = 149;
|
||||
int32_t cpu = -1;
|
||||
int32_t pid = -1;
|
||||
bool challenge = false;
|
||||
int32_t type = 0;
|
||||
uint64_t sample_period = 0;
|
||||
uint64_t sample_type = 0;
|
||||
uint64_t config = 0;
|
||||
int clockid = CLOCK_MONOTONIC_RAW;
|
||||
int comm = 0;
|
||||
int mmap_ = 0;
|
||||
int task = 0;
|
||||
int exclude_idle = 0;
|
||||
int fd = -1;
|
||||
int use_clockid = 0;
|
||||
int r;
|
||||
|
||||
assert (msg);
|
||||
|
||||
r = sd_bus_message_enter_container (msg, SD_BUS_TYPE_ARRAY, "{sv}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
r = sd_bus_message_enter_container (msg, SD_BUS_TYPE_DICT_ENTRY, "sv");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
r = sd_bus_message_read (msg, "s", &name);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
r = sd_bus_message_enter_container (msg, SD_BUS_TYPE_VARIANT, NULL);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (strcmp (name, "disabled") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "b", &disabled);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "wakeup_events") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "u", &wakeup_events);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "clockid") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "i", &clockid);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "comm") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "b", &comm);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "exclude_idle") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "b", &exclude_idle);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "mmap") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "b", &mmap_);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "config") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "t", &config);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "sample_period") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "t", &sample_period);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "sample_type") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "t", &sample_type);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "task") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "b", &task);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "type") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "u", &type);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
else if (strcmp (name, "use_clockid") == 0)
|
||||
{
|
||||
r = sd_bus_message_read (msg, "b", &use_clockid);
|
||||
if (r < 0)
|
||||
GOTO (cleanup);
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container (msg);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
sd_bus_message_exit_container (msg);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container (msg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read (msg, "iit", &pid, &cpu, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (pid < -1 || cpu < -1)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_return (msg, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Authorize peer */
|
||||
r = bus_test_polkit (msg,
|
||||
CAP_SYS_ADMIN,
|
||||
"org.gnome.sysprof2.perf-event-open",
|
||||
NULL,
|
||||
UID_INVALID,
|
||||
&challenge,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r == 0)
|
||||
return -EACCES;
|
||||
|
||||
if (!use_clockid || clockid < 0)
|
||||
clockid = CLOCK_MONOTONIC_RAW;
|
||||
|
||||
attr.comm = !!comm;
|
||||
attr.config = config;
|
||||
attr.disabled = disabled;
|
||||
attr.exclude_idle = !!exclude_idle;
|
||||
attr.mmap = !!mmap_;
|
||||
attr.sample_period = sample_period;
|
||||
attr.sample_type = sample_type;
|
||||
attr.size = sizeof attr;
|
||||
attr.task = !!task;
|
||||
attr.type = type;
|
||||
attr.clockid = clockid;
|
||||
attr.use_clockid = use_clockid;
|
||||
attr.wakeup_events = wakeup_events;
|
||||
|
||||
fd = _perf_event_open (&attr, pid, cpu, -1, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to open perf event stream: %s\n",
|
||||
strerror (errno));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sd_bus_message_append_basic (reply, SD_BUS_TYPE_UNIX_FD, &fd);
|
||||
r = sd_bus_send (NULL, reply, NULL);
|
||||
sd_bus_message_unref (reply);
|
||||
|
||||
close (fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable sysprofd_vtable[] = {
|
||||
SD_BUS_VTABLE_START (0),
|
||||
SD_BUS_METHOD ("PerfEventOpen", "a{sv}iit", "h", sysprofd_perf_event_open, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
sd_bus_slot *slot = NULL;
|
||||
sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
||||
/* Connect to the system bus */
|
||||
r = sd_bus_default_system (&bus);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to connect to system bus: %s\n",
|
||||
strerror (-r));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Install our object */
|
||||
r = sd_bus_add_object_vtable (bus,
|
||||
&slot,
|
||||
"/org/gnome/Sysprof2",
|
||||
"org.gnome.Sysprof2",
|
||||
sysprofd_vtable,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to install object on bus: %s\n",
|
||||
strerror (-r));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Request our well-known name on the bus */
|
||||
r = sd_bus_request_name (bus, "org.gnome.Sysprof2", 0);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to register name on the bus: %s\n",
|
||||
strerror (-r));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Process requests */
|
||||
r = sd_bus_process (bus, NULL);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to process bus: %s\n",
|
||||
strerror (-r));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* If we processed a request, continue processing */
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
/* Wait for the next request to process */
|
||||
r = sd_bus_wait (bus, BUS_TIMEOUT_USEC);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to wait on bus: %s\n",
|
||||
strerror (-r));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we timed out, we can expire, we will be auto-started by
|
||||
* systemd or dbus on the next activation request.
|
||||
*/
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
failure:
|
||||
sd_bus_slot_unref (slot);
|
||||
sd_bus_unref (bus);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user