nspawn: introduce the new /machine/ tree in the cgroup tree and move containers there

Containers will now carry a label (normally derived from the root
directory name, but configurable by the user), and the container's root
cgroup is /machine/<label>. This label is called "machine name", and can
cover both containers and VMs (as soon as libvirt also makes use of
/machine/).

libsystemd-login can be used to query the machine name from a process.

This patch also includes numerous clean-ups for the cgroup code.
This commit is contained in:
Lennart Poettering 2013-04-16 04:36:06 +02:00
parent cec4ead904
commit 7027ff61a3
20 changed files with 571 additions and 526 deletions

View File

@ -47,7 +47,8 @@
<refname>sd_pid_get_unit</refname>
<refname>sd_pid_get_user_unit</refname>
<refname>sd_pid_get_owner_uid</refname>
<refpurpose>Determine session, service or owner of a session of a specific PID</refpurpose>
<refname>sd_pid_get_machine_name</refname>
<refpurpose>Determine session, service, owner of a session or container/VM of a specific PID</refpurpose>
</refnamediv>
<refsynopsisdiv>
@ -77,6 +78,12 @@
<paramdef>pid_t <parameter>pid</parameter></paramdef>
<paramdef>uid_t* <parameter>uid</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_pid_get_machine_name</function></funcdef>
<paramdef>pid_t <parameter>pid</parameter></paramdef>
<paramdef>char** <parameter>name</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@ -108,7 +115,7 @@
function will fail. (More specifically: this call will
not work for processes that are part of user units,
use <function>sd_pid_get_user_unit()</function> for
that.) The returned string needs to be freed with the
that.) The returned string needs to be freed with the
libc
<citerefentry><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
@ -131,6 +138,14 @@
and not being a shared process of a user this function
will fail.</para>
<para><function>sd_pid_machine_name()</function> may
be used to determine the name of the VM or container
is a member of. The machine name is a short string,
suitable for usage in file system paths. The returned
string needs to be freed with the libc
<citerefentry><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
<para>If the <literal>pid</literal> parameter of any
of these functions is passed as 0 the operation is
executed for the calling process.</para>
@ -149,10 +164,11 @@
<para>The <function>sd_pid_get_session()</function>,
<function>sd_pid_get_unit()</function>,
<function>sd_pid_get_user_unit()</function>, and
<function>sd_pid_get_owner_uid()</function> interfaces
are available as shared library, which can be compiled
and linked to with the
<function>sd_pid_get_user_unit()</function>,
<function>sd_pid_get_owner_uid()</function> and
<function>sd_pid_get_machine_name()</function>
interfaces are available as shared library, which can
be compiled and linked to with the
<literal>libsystemd-login</literal>
<citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
file.</para>

View File

@ -202,6 +202,21 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-M</option></term>
<term><option>--machine=</option></term>
<listitem><para>Sets the machine name
for this container. This name may be
used to identify this container on the
host, and is used to initialize the
container's hostname (which the
container can choose to override,
however). If not specified the last
component of the root directory of the
container is used.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--uuid=</option></term>

View File

@ -171,19 +171,14 @@ int main(int argc, char *argv[]) {
arg_kernel_threads, output_flags);
} else {
char _cleanup_free_ *root = NULL;
const char *t = NULL;
r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root);
if (r < 0)
t = "/";
else {
if (endswith(root, "/system"))
root[strlen(root)-7] = 0;
t = root[0] ? root : "/";
r = cg_get_root_path(&root);
if (r < 0) {
log_error("Failed to get root path: %s", strerror(-r));
goto finish;
}
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0,
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0,
arg_kernel_threads, output_flags);
}
}

View File

@ -320,8 +320,9 @@ int cgroup_bonding_is_empty_list(CGroupBonding *first) {
int manager_setup_cgroup(Manager *m) {
_cleanup_free_ char *current = NULL, *path = NULL;
char suffix_buffer[sizeof("/systemd-") + DECIMAL_STR_MAX(pid_t)];
const char *suffix;
int r;
char suffix[sizeof("/systemd-") + DECIMAL_STR_MAX(pid_t)];
assert(m);
@ -332,17 +333,17 @@ int manager_setup_cgroup(Manager *m) {
}
/* 1. Determine hierarchy */
r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current);
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &current);
if (r < 0) {
log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
return r;
}
if (m->running_as == SYSTEMD_SYSTEM)
strcpy(suffix, "/system");
suffix = "/system";
else {
snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
char_array_0(suffix);
sprintf(suffix_buffer, "/systemd-%lu", (unsigned long) getpid());
suffix = suffix_buffer;
}
free(m->cgroup_hierarchy);
@ -350,11 +351,14 @@ int manager_setup_cgroup(Manager *m) {
/* We probably got reexecuted and can continue to use our root cgroup */
m->cgroup_hierarchy = current;
current = NULL;
} else {
/* We need a new root cgroup */
m->cgroup_hierarchy = NULL;
if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0)
if (streq(current, "/"))
m->cgroup_hierarchy = strdup(suffix);
else
m->cgroup_hierarchy = strappend(current, suffix);
if (!m->cgroup_hierarchy)
return log_oom();
}
@ -509,7 +513,7 @@ Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
if (pid <= 1)
return NULL;
if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
return NULL;
l = hashmap_get(m->cgroup_bondings, group);

View File

@ -1034,7 +1034,7 @@ int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
unit_remove_drop_in(u, runtime, controller);
/* Try to migrate the old group away */
if (cg_get_by_pid(controller, 0, &target) >= 0)
if (cg_pid_get_path(controller, 0, &target) >= 0)
cgroup_bonding_migrate_to(u->cgroup_bondings, target, false);
cgroup_bonding_free(b, true);

View File

@ -420,36 +420,6 @@ void server_vacuum(Server *s) {
s->cached_available_space_timestamp = 0;
}
static char *shortened_cgroup_path(pid_t pid) {
int r;
char _cleanup_free_ *process_path = NULL, *init_path = NULL;
char *path;
assert(pid > 0);
r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &process_path);
if (r < 0)
return NULL;
r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &init_path);
if (r < 0)
return NULL;
if (endswith(init_path, "/system"))
init_path[strlen(init_path) - 7] = 0;
else if (streq(init_path, "/"))
init_path[0] = 0;
if (startswith(process_path, init_path)) {
path = strdup(process_path + strlen(init_path));
} else {
path = process_path;
process_path = NULL;
}
return path;
}
bool shall_try_append_again(JournalFile *f, int r) {
/* -E2BIG Hit configured limit
@ -620,8 +590,8 @@ static void dispatch_message_real(
IOVEC_SET_STRING(iovec[n++], audit_loginuid);
#endif
t = shortened_cgroup_path(ucred->pid);
if (t) {
r = cg_pid_get_path(NULL, ucred->pid, &t);
if (r >= 0) {
cgroup = strappend("_SYSTEMD_CGROUP=", t);
free(t);
@ -630,7 +600,8 @@ static void dispatch_message_real(
}
#ifdef HAVE_LOGIND
if (sd_pid_get_session(ucred->pid, &t) >= 0) {
r = cg_pid_get_session(ucred->pid, &t);
if (r >= 0) {
session = strappend("_SYSTEMD_SESSION=", t);
free(t);
@ -773,7 +744,7 @@ void server_dispatch_message(
const char *unit_id,
int priority) {
int rl;
int rl, r;
char _cleanup_free_ *path = NULL;
char *c;
@ -789,8 +760,8 @@ void server_dispatch_message(
if (!ucred)
goto finish;
path = shortened_cgroup_path(ucred->pid);
if (!path)
r = cg_pid_get_path_shifted(ucred->pid, NULL, &path);
if (r < 0)
goto finish;
/* example: /user/lennart/3/foobar

View File

@ -68,4 +68,5 @@ global:
LIBSYSTEMD_LOGIN_202 {
global:
sd_pid_get_user_unit;
sd_pid_get_machine_name;
} LIBSYSTEMD_LOGIN_201;

View File

@ -506,7 +506,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
dbus_message_iter_get_basic(&iter, &kill_processes);
r = cg_pid_get_cgroup(leader, NULL, &cgroup);
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, leader, &cgroup);
if (r < 0)
goto fail;

View File

@ -436,7 +436,6 @@ static int session_create_one_group(Session *s, const char *controller, const ch
int r;
assert(s);
assert(controller);
assert(path);
if (s->leader > 0) {

View File

@ -1100,21 +1100,18 @@ int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) {
}
int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
char *p;
_cleanup_free_ char *p = NULL;
int r;
assert(m);
assert(pid >= 1);
assert(session);
r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &p);
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &p);
if (r < 0)
return r;
r = manager_get_session_by_cgroup(m, p, session);
free(p);
return r;
return manager_get_session_by_cgroup(m, p, session);
}
void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {

View File

@ -33,51 +33,19 @@
#include "fileio.h"
_public_ int sd_pid_get_session(pid_t pid, char **session) {
int r;
char *cgroup, *p;
if (pid < 0)
return -EINVAL;
if (!session)
return -EINVAL;
r = cg_pid_get_cgroup(pid, NULL, &cgroup);
if (r < 0)
return r;
if (!startswith(cgroup, "/user/")) {
free(cgroup);
return -ENOENT;
}
p = strchr(cgroup + 6, '/');
if (!p) {
free(cgroup);
return -ENOENT;
}
p++;
if (startswith(p, "shared/") || streq(p, "shared")) {
free(cgroup);
return -ENOENT;
}
p = strndup(p, strcspn(p, "/"));
free(cgroup);
if (!p)
return -ENOMEM;
*session = p;
return 0;
return cg_pid_get_session(pid, session);
}
_public_ int sd_pid_get_unit(pid_t pid, char **unit) {
if (pid < 0)
return -EINVAL;
if (!unit)
return -EINVAL;
@ -88,13 +56,22 @@ _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
if (pid < 0)
return -EINVAL;
if (!unit)
return -EINVAL;
return cg_pid_get_user_unit(pid, unit);
}
_public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
if (pid < 0)
return -EINVAL;
if (!name)
return -EINVAL;
return cg_pid_get_machine_name(pid, name);
}
_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
int r;
char *root, *cgroup, *p, *cc;
@ -106,7 +83,7 @@ _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
if (!uid)
return -EINVAL;
r = cg_pid_get_cgroup(pid, &root, &cgroup);
r = cg_pid_get_path_shifted(pid, &root, &cgroup);
if (r < 0)
return r;

View File

@ -75,6 +75,7 @@ static char *arg_directory = NULL;
static char *arg_user = NULL;
static char **arg_controllers = NULL;
static char *arg_uuid = NULL;
static char *arg_machine = NULL;
static bool arg_private_network = false;
static bool arg_read_only = false;
static bool arg_boot = false;
@ -113,13 +114,14 @@ static int help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
"Spawn a minimal namespace container for debugging, testing and building.\n\n"
" -h --help Show this help\n"
" --version Print version string\n"
" --version Print version string\n"
" -D --directory=NAME Root directory for the container\n"
" -b --boot Boot up full system (i.e. invoke init)\n"
" -u --user=USER Run the command under specified user or uid\n"
" -C --controllers=LIST Put the container in specified comma-separated\n"
" cgroup hierarchies\n"
" --uuid=UUID Set a specific machine UUID for the container\n"
" -M --machine=NAME Set the machine name for the container\n"
" --private-network Disable network in container\n"
" --read-only Mount the root directory read-only\n"
" --capability=CAP In addition to the default, retain specified\n"
@ -161,6 +163,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "link-journal", required_argument, NULL, ARG_LINK_JOURNAL },
{ "bind", required_argument, NULL, ARG_BIND },
{ "bind-ro", required_argument, NULL, ARG_BIND_RO },
{ "machine", required_argument, NULL, 'M' },
{ NULL, 0, NULL, 0 }
};
@ -194,22 +197,19 @@ static int parse_argv(int argc, char *argv[]) {
case 'u':
free(arg_user);
if (!(arg_user = strdup(optarg))) {
log_error("Failed to duplicate user name.");
return -ENOMEM;
}
arg_user = strdup(optarg);
if (!arg_user)
return log_oom();
break;
case 'C':
strv_free(arg_controllers);
arg_controllers = strv_split(optarg, ",");
if (!arg_controllers) {
log_error("Failed to split controllers list.");
return -ENOMEM;
}
strv_uniq(arg_controllers);
if (!arg_controllers)
return log_oom();
cg_shorten_controllers(arg_controllers);
break;
case ARG_PRIVATE_NETWORK:
@ -224,6 +224,19 @@ static int parse_argv(int argc, char *argv[]) {
arg_uuid = optarg;
break;
case 'M':
if (!hostname_is_valid(optarg)) {
log_error("Invalid machine name: %s", optarg);
return -EINVAL;
}
free(arg_machine);
arg_machine = strdup(optarg);
if (!arg_machine)
return log_oom();
break;
case ARG_READ_ONLY:
arg_read_only = true;
break;
@ -743,25 +756,11 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
}
static int setup_hostname(void) {
char *hn;
int r = 0;
hn = path_get_file_name(arg_directory);
if (hn) {
hn = strdup(hn);
if (!hn)
return -ENOMEM;
if (sethostname(arg_machine, strlen(arg_machine)) < 0)
return -errno;
hostname_cleanup(hn);
if (!isempty(hn))
if (sethostname(hn, strlen(hn)) < 0)
r = -errno;
free(hn);
}
return r;
return 0;
}
static int setup_journal(const char *directory) {
@ -896,6 +895,25 @@ static int setup_journal(const char *directory) {
return 0;
}
static int setup_cgroup(const char *path) {
char **c;
int r;
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, path, 1);
if (r < 0) {
log_error("Failed to create cgroup: %s", strerror(-r));
return r;
}
STRV_FOREACH(c, arg_controllers) {
r = cg_create_and_attach(*c, path, 1);
if (r < 0)
log_warning("Failed to create cgroup in controller %s: %s", *c, strerror(-r));
}
return 0;
}
static int drop_capabilities(void) {
return capability_bounding_set_drop(~arg_retain, false);
}
@ -1159,9 +1177,9 @@ finish:
int main(int argc, char *argv[]) {
pid_t pid = 0;
int r = EXIT_FAILURE, k;
char *oldcg = NULL, *newcg = NULL;
char **controller = NULL;
int master = -1, n_fd_passed;
_cleanup_free_ char *machine_root = NULL, *newcg = NULL;
_cleanup_close_ int master = -1;
int n_fd_passed;
const char *console = NULL;
struct termios saved_attr, raw_attr;
sigset_t mask;
@ -1193,6 +1211,20 @@ int main(int argc, char *argv[]) {
path_kill_slashes(arg_directory);
if (!arg_machine) {
arg_machine = strdup(path_get_file_name(arg_directory));
if (!arg_machine) {
log_oom();
goto finish;
}
hostname_cleanup(arg_machine);
if (isempty(arg_machine)) {
log_error("Failed to determine machine name automatically, please use -M.");
goto finish;
}
}
if (geteuid() != 0) {
log_error("Need to be root.");
goto finish;
@ -1225,27 +1257,26 @@ int main(int argc, char *argv[]) {
fdset_close_others(fds);
log_open();
k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg);
k = cg_get_machine_path(&machine_root);
if (k < 0) {
log_error("Failed to determine current cgroup: %s", strerror(-k));
log_error("Failed to determine machine cgroup path: %s", strerror(-k));
goto finish;
}
if (asprintf(&newcg, "%s/nspawn-%lu", oldcg, (unsigned long) getpid()) < 0) {
newcg = strjoin(machine_root, "/", arg_machine, NULL);
if (!newcg) {
log_error("Failed to allocate cgroup path.");
goto finish;
}
k = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, newcg, 0);
if (k < 0) {
log_error("Failed to create cgroup: %s", strerror(-k));
goto finish;
}
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, newcg, false);
if (r <= 0 && r != -ENOENT) {
log_error("Container already running.");
STRV_FOREACH(controller, arg_controllers) {
k = cg_create_and_attach(*controller, newcg, 0);
if (k < 0)
log_warning("Failed to create cgroup in controller %s: %s", *controller, strerror(-k));
free(newcg);
newcg = NULL;
goto finish;
}
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
@ -1279,7 +1310,7 @@ int main(int argc, char *argv[]) {
}
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) {
log_error("Failed to create kmsg socket pair");
log_error("Failed to create kmsg socket pair.");
goto finish;
}
@ -1382,6 +1413,9 @@ int main(int argc, char *argv[]) {
goto child_fail;
}
if (setup_cgroup(newcg) < 0)
goto child_fail;
/* Mark everything as slave, so that we still
* receive mounts from the real root, but don't
* propagate mounts to the real root. */
@ -1547,7 +1581,7 @@ int main(int argc, char *argv[]) {
}
if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", n_fd_passed) < 0) ||
(asprintf((char **)(envp + n_env++), "LISTEN_PID=%lu", (unsigned long) getpid()) < 0)) {
(asprintf((char **)(envp + n_env++), "LISTEN_PID=%lu", (unsigned long) 1) < 0)) {
log_oom();
goto child_fail;
}
@ -1640,21 +1674,14 @@ finish:
if (saved_attr_valid)
tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
if (master >= 0)
close_nointr_nofail(master);
close_pipe(kmsg_socket_pair);
if (oldcg)
cg_attach(SYSTEMD_CGROUP_CONTROLLER, oldcg, 0);
if (newcg)
cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, newcg, true);
free(arg_directory);
free(arg_machine);
strv_free(arg_controllers);
free(oldcg);
free(newcg);
fdset_free(fds);

View File

@ -40,9 +40,6 @@ int cg_create(const char *controller, const char *path, const char *suffix) {
_cleanup_free_ char *fs = NULL;
int r;
assert(controller);
assert(path);
r = cg_get_path_and_check(controller, path, suffix, &fs);
if (r < 0)
return r;
@ -65,8 +62,6 @@ int cg_create(const char *controller, const char *path, const char *suffix) {
int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
int r, q;
assert(controller);
assert(path);
assert(pid >= 0);
r = cg_create(controller, path, NULL);

View File

@ -104,20 +104,20 @@ static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsi
static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
char *fn;
FILE *f;
_cleanup_fclose_ FILE *f = NULL;
size_t n = 0, n_allocated = 0;
pid_t *pids = NULL;
char *p;
_cleanup_free_ pid_t *pids = NULL;
char *p = NULL;
pid_t pid;
int r;
r = cg_fix_path(path, &p);
r = cg_mangle_path(path, &p);
if (r < 0)
return r;
r = asprintf(&fn, "%s/cgroup.procs", p);
fn = strappend(p, "/cgroup.procs");
free(p);
if (r < 0)
if (!fn)
return -ENOMEM;
f = fopen(fn, "re");
@ -136,10 +136,8 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
n_allocated = MAX(16U, n*2U);
npids = realloc(pids, sizeof(pid_t) * n_allocated);
if (!npids) {
r = -ENOMEM;
goto finish;
}
if (!npids)
return -ENOMEM;
pids = npids;
}
@ -149,26 +147,18 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
}
if (r < 0)
goto finish;
return r;
if (n > 0)
show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
r = 0;
finish:
free(pids);
if (f)
fclose(f);
return r;
return 0;
}
int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
DIR *d;
char *last = NULL;
char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
_cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
_cleanup_closedir_ DIR *d = NULL;
char *gn = NULL;
bool shown_pids = false;
int r;
@ -180,30 +170,24 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (!prefix)
prefix = "";
r = cg_fix_path(path, &fn);
r = cg_mangle_path(path, &fn);
if (r < 0)
return r;
d = opendir(fn);
if (!d) {
free(fn);
if (!d)
return -errno;
}
while ((r = cg_read_subgroup(d, &gn)) > 0) {
char *k;
_cleanup_free_ char *k = NULL;
r = asprintf(&k, "%s/%s", fn, gn);
k = strjoin(fn, "/", gn, NULL);
free(gn);
if (r < 0) {
r = -ENOMEM;
goto finish;
}
if (!k)
return -ENOMEM;
if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0) {
free(k);
if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
continue;
}
if (!shown_pids) {
show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
@ -216,11 +200,8 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (!p1) {
p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT));
if (!p1) {
free(k);
r = -ENOMEM;
goto finish;
}
if (!p1)
return -ENOMEM;
}
show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
@ -228,10 +209,11 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
}
last = k;
k = NULL;
}
if (r < 0)
goto finish;
return r;
if (!shown_pids)
show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
@ -242,43 +224,27 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (!p2) {
p2 = strappend(prefix, " ");
if (!p2) {
r = -ENOMEM;
goto finish;
}
if (!p2)
return -ENOMEM;
}
show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
}
r = 0;
finish:
free(p1);
free(p2);
free(last);
free(fn);
closedir(d);
return r;
return 0;
}
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
char *p;
_cleanup_free_ char *p = NULL;
int r;
assert(controller);
assert(path);
r = cg_get_path(controller, path, NULL, &p);
if (r < 0)
return r;
r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
free(p);
return r;
return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
}
static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) {
@ -295,8 +261,7 @@ static int show_extra_pids(const char *controller, const char *path, const char
if (n_columns <= 0)
n_columns = columns();
if (!prefix)
prefix = "";
prefix = strempty(prefix);
copy = new(pid_t, n_pids);
if (!copy)
@ -305,7 +270,7 @@ static int show_extra_pids(const char *controller, const char *path, const char
for (i = 0, j = 0; i < n_pids; i++) {
char _cleanup_free_ *k = NULL;
r = cg_get_by_pid(controller, pids[i], &k);
r = cg_pid_get_path(controller, pids[i], &k);
if (r < 0)
return r;
@ -323,7 +288,6 @@ static int show_extra_pids(const char *controller, const char *path, const char
int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
int r;
assert(controller);
assert(path);
r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
@ -334,8 +298,8 @@ int show_cgroup_and_extra(const char *controller, const char *path, const char *
}
int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
int r;
_cleanup_free_ char *controller = NULL, *path = NULL;
int r;
assert(spec);

File diff suppressed because it is too large Load Diff

View File

@ -44,11 +44,12 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
int cg_split_spec(const char *spec, char **controller, char **path);
int cg_join_spec(const char *controller, const char *path, char **spec);
int cg_fix_path(const char *path, char **result);
int cg_mangle_path(const char *path, char **result);
int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs);
int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs);
int cg_get_by_pid(const char *controller, pid_t pid, char **path);
int cg_pid_get_path(const char *controller, pid_t pid, char **path);
int cg_trim(const char *controller, const char *path, bool delete_root);
@ -68,16 +69,24 @@ int cg_is_empty(const char *controller, const char *path, bool ignore_self);
int cg_is_empty_by_spec(const char *spec, bool ignore_self);
int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self);
int cg_get_root_path(char **path);
int cg_get_system_path(char **path);
int cg_get_user_path(char **path);
int cg_get_machine_path(char **path);
int cg_path_get_session(const char *path, char **session);
int cg_path_get_unit(const char *path, char **unit);
int cg_path_get_user_unit(const char *path, char **unit);
int cg_path_get_machine_name(const char *path, char **machine);
int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup);
int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup);
int cg_pid_get_session(pid_t pid, char **session);
int cg_pid_get_unit(pid_t pid, char **unit);
int cg_pid_get_user_unit(pid_t pid, char **unit);
int cg_pid_get_machine_name(pid_t pid, char **machine);
int cg_cgroup_to_unit(const char *cgroup, char **unit);
int cg_path_decode_unit(const char *cgroup, char **unit);
char **cg_shorten_controllers(char **controllers);

View File

@ -64,12 +64,16 @@ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid);
/* Get systemd unit (i.e. service) name from PID, for system
* services. This will return an error for non-service processes. */
int sd_pid_get_unit(pid_t, char **unit);
int sd_pid_get_unit(pid_t pid, char **unit);
/* Get systemd unit (i.e. service) name from PID, for user
* services. This will return an error for non-user-service
* processes. */
int sd_pid_get_user_unit(pid_t, char **unit);
int sd_pid_get_user_unit(pid_t pid, char **unit);
/* Get machine name from PID, for processes assigned to VM or
* container. This will return an error for non-service processes. */
int sd_pid_get_machine_name(pid_t pid, char **name);
/* Get state from uid. Possible states: offline, lingering, online, active, closing */
int sd_uid_get_state(uid_t uid, char**state);

View File

@ -24,20 +24,20 @@
#include "util.h"
#include "cgroup-util.h"
static void check_c_t_u(const char *path, int code, const char *result) {
static void check_p_d_u(const char *path, int code, const char *result) {
_cleanup_free_ char *unit = NULL;
assert_se(cg_cgroup_to_unit(path, &unit) == code);
assert_se(cg_path_decode_unit(path, &unit) == code);
assert_se(streq_ptr(unit, result));
}
static void test_cgroup_to_unit(void) {
check_c_t_u("getty@.service/tty2", 0, "getty@tty2.service");
check_c_t_u("getty@.service/tty2/xxx", 0, "getty@tty2.service");
check_c_t_u("getty@.service/", -EINVAL, NULL);
check_c_t_u("getty@.service", -EINVAL, NULL);
check_c_t_u("getty.service", 0, "getty.service");
check_c_t_u("getty", -EINVAL, NULL);
static void test_path_decode_unit(void) {
check_p_d_u("getty@.service/tty2", 0, "getty@tty2.service");
check_p_d_u("getty@.service/tty2/xxx", 0, "getty@tty2.service");
check_p_d_u("getty@.service/", -EINVAL, NULL);
check_p_d_u("getty@.service", -EINVAL, NULL);
check_p_d_u("getty.service", 0, "getty.service");
check_p_d_u("getty", -EINVAL, NULL);
}
static void check_p_g_u(const char *path, int code, const char *result) {
@ -62,7 +62,9 @@ static void test_path_get_unit(void) {
check_p_g_u("/system/getty@tty6.service/tty5", 0, "getty@tty6.service");
check_p_g_u("sadfdsafsda", -ENOENT, NULL);
check_p_g_u("/system/getty####@tty6.service/tty5", -EINVAL, NULL);
}
static void test_path_get_user_unit(void) {
check_p_g_u_u("/user/lennart/2/systemd-21548/foobar.service", 0, "foobar.service");
check_p_g_u_u("/user/lennart/2/systemd-21548/foobar.service/waldo", 0, "foobar.service");
check_p_g_u_u("/user/lennart/2/systemd-21548/foobar.service/waldo/uuuux", 0, "foobar.service");
@ -71,9 +73,27 @@ static void test_path_get_unit(void) {
check_p_g_u_u("/user/lennart/2/systemd-21548/foobar@.service/pie/pa/po", 0, "foobar@pie.service");
}
static void test_get_paths(void) {
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL;
assert_se(cg_get_root_path(&a) >= 0);
log_info("Root = %s", a);
assert_se(cg_get_system_path(&b) >= 0);
log_info("System = %s", b);
assert_se(cg_get_user_path(&c) >= 0);
log_info("User = %s", c);
assert_se(cg_get_machine_path(&d) >= 0);
log_info("Machine = %s", d);
}
int main(void) {
test_cgroup_to_unit();
test_path_decode_unit();
test_path_get_unit();
test_path_get_user_unit();
test_get_paths();
return 0;
}

View File

@ -37,19 +37,19 @@ int main(int argc, char*argv[]) {
assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c", NULL) == 0);
assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0);
assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
assert_se(streq(path, "/test-b"));
free(path);
assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) == 0);
assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
assert_se(path_equal(path, "/test-a"));
free(path);
assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", 0) == 0);
assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
assert_se(path_equal(path, "/test-b/test-d"));
free(path);

View File

@ -1104,7 +1104,7 @@ int main(int argc, char *argv[])
}
/* get our own cgroup, we regularly kill everything udev has left behind */
if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &udev_cgroup) < 0)
if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &udev_cgroup) < 0)
udev_cgroup = NULL;
} else {
/* open control and netlink socket */