summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-04-16 04:36:06 +0200
committerLennart Poettering <lennart@poettering.net>2013-04-16 04:41:21 +0200
commit7027ff61a34a12487712b382a061c654acc3a679 (patch)
tree05e9374a566d6accdd962dd4dc6d7076b9304122 /src
parentcec4ead904978b07db2154c618eeb48d3102da66 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/cgls/cgls.c15
-rw-r--r--src/core/cgroup.c22
-rw-r--r--src/core/dbus-unit.c2
-rw-r--r--src/journal/journald-server.c43
-rw-r--r--src/login/libsystemd-login.sym1
-rw-r--r--src/login/logind-dbus.c2
-rw-r--r--src/login/logind-session.c1
-rw-r--r--src/login/logind.c9
-rw-r--r--src/login/sd-login.c47
-rw-r--r--src/nspawn/nspawn.c131
-rw-r--r--src/shared/cgroup-label.c5
-rw-r--r--src/shared/cgroup-show.c100
-rw-r--r--src/shared/cgroup-util.c603
-rw-r--r--src/shared/cgroup-util.h17
-rw-r--r--src/systemd/sd-login.h8
-rw-r--r--src/test/test-cgroup-util.c40
-rw-r--r--src/test/test-cgroup.c6
-rw-r--r--src/udev/udevd.c2
18 files changed, 534 insertions, 520 deletions
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index e649b75df6..e01a7b13a1 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -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);
}
}
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index a248252bcd..83df0f3c9a 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -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);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 5f1b2afd5b..8c1ce61151 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -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);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index be84323a6c..a540fcb421 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -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
diff --git a/src/login/libsystemd-login.sym b/src/login/libsystemd-login.sym
index 9048de86a9..f4cd209700 100644
--- a/src/login/libsystemd-login.sym
+++ b/src/login/libsystemd-login.sym
@@ -68,4 +68,5 @@ global:
LIBSYSTEMD_LOGIN_202 {
global:
sd_pid_get_user_unit;
+ sd_pid_get_machine_name;
} LIBSYSTEMD_LOGIN_201;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index d957bd7de5..228a8389ee 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -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;
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index da7ce42015..2f7ab3451f 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -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) {
diff --git a/src/login/logind.c b/src/login/logind.c
index aa3e5f0914..caed149ad6 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -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) {
diff --git a/src/login/sd-login.c b/src/login/sd-login.c
index 4c918f2105..c97d75c000 100644
--- a/src/login/sd-login.c
+++ b/src/login/sd-login.c
@@ -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;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index b90ccc53ef..c257682451 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -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;
-
- hostname_cleanup(hn);
- if (!isempty(hn))
- if (sethostname(hn, strlen(hn)) < 0)
- r = -errno;
-
- free(hn);
- }
+ if (sethostname(arg_machine, strlen(arg_machine)) < 0)
+ return -errno;
- 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);
diff --git a/src/shared/cgroup-label.c b/src/shared/cgroup-label.c
index a0b486e51e..5b5163c250 100644
--- a/src/shared/cgroup-label.c
+++ b/src/shared/cgroup-label.c
@@ -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);
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 966af5e24c..9ee532ca22 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -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);
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 075260783c..0749b61154 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -40,11 +40,10 @@
#include "fileio.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
- char *fs;
- int r;
+ _cleanup_free_ char *fs = NULL;
FILE *f;
+ int r;
- assert(path);
assert(_f);
r = cg_get_path(controller, path, "cgroup.procs", &fs);
@@ -52,8 +51,6 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **_f)
return r;
f = fopen(fs, "re");
- free(fs);
-
if (!f)
return -errno;
@@ -62,11 +59,10 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **_f)
}
int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
- char *fs;
- int r;
+ _cleanup_free_ char *fs = NULL;
FILE *f;
+ int r;
- assert(path);
assert(_f);
r = cg_get_path(controller, path, "tasks", &fs);
@@ -74,8 +70,6 @@ int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
return r;
f = fopen(fs, "re");
- free(fs);
-
if (!f)
return -errno;
@@ -89,6 +83,9 @@ int cg_read_pid(FILE *f, pid_t *_pid) {
/* Note that the cgroup.procs might contain duplicates! See
* cgroups.txt for details. */
+ assert(f);
+ assert(_pid);
+
errno = 0;
if (fscanf(f, "%lu", &ul) != 1) {
@@ -106,11 +103,10 @@ int cg_read_pid(FILE *f, pid_t *_pid) {
}
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
- char *fs;
+ _cleanup_free_ char *fs = NULL;
int r;
DIR *d;
- assert(path);
assert(_d);
/* This is not recursive! */
@@ -120,8 +116,6 @@ int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
return r;
d = opendir(fs);
- free(fs);
-
if (!d)
return -errno;
@@ -133,9 +127,9 @@ int cg_read_subgroup(DIR *d, char **fn) {
struct dirent *de;
assert(d);
+ assert(fn);
- errno = 0;
- while ((de = readdir(d))) {
+ FOREACH_DIRENT(de, d, return -errno) {
char *b;
if (de->d_type != DT_DIR)
@@ -145,21 +139,19 @@ int cg_read_subgroup(DIR *d, char **fn) {
streq(de->d_name, ".."))
continue;
- if (!(b = strdup(de->d_name)))
+ b = strdup(de->d_name);
+ if (!b)
return -ENOMEM;
*fn = b;
return 1;
}
- if (errno)
- return -errno;
-
return 0;
}
int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
- char *p;
+ _cleanup_free_ char *p = NULL;
int r;
r = cg_get_path(controller, path, NULL, &p);
@@ -172,61 +164,59 @@ int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
/* If the sticky bit is set don't remove the directory */
tasks = strappend(p, "/tasks");
- if (!tasks) {
- free(p);
+ if (!tasks)
return -ENOMEM;
- }
r = file_is_priv_sticky(tasks);
free(tasks);
- if (r > 0) {
- free(p);
+ if (r > 0)
return 0;
- }
}
r = rmdir(p);
- free(p);
+ if (r < 0 && errno != ENOENT)
+ return -errno;
- return (r < 0 && errno != ENOENT) ? -errno : 0;
+ return 0;
}
int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
+ _cleanup_set_free_ Set *allocated_set = NULL;
bool done = false;
int r, ret = 0;
pid_t my_pid;
- FILE *f = NULL;
- Set *allocated_set = NULL;
- assert(controller);
- assert(path);
assert(sig >= 0);
/* This goes through the tasks list and kills them all. This
* is repeated until no further processes are added to the
* tasks list, to properly handle forking processes */
- if (!s)
- if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
+ if (!s) {
+ s = allocated_set = set_new(trivial_hash_func, trivial_compare_func);
+ if (!s)
return -ENOMEM;
+ }
my_pid = getpid();
do {
+ _cleanup_fclose_ FILE *f = NULL;
pid_t pid = 0;
done = true;
- if ((r = cg_enumerate_processes(controller, path, &f)) < 0) {
+ r = cg_enumerate_processes(controller, path, &f);
+ if (r < 0) {
if (ret >= 0 && r != -ENOENT)
- ret = r;
+ return r;
- goto finish;
+ return ret;
}
while ((r = cg_read_pid(f, &pid)) > 0) {
- if (pid == my_pid && ignore_self)
+ if (ignore_self && pid == my_pid)
continue;
if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
@@ -247,100 +237,77 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
done = false;
- if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
+ r = set_put(s, LONG_TO_PTR(pid));
+ if (r < 0) {
if (ret >= 0)
- ret = r;
+ return r;
- goto finish;
+ return ret;
}
}
if (r < 0) {
if (ret >= 0)
- ret = r;
+ return r;
- goto finish;
+ return ret;
}
- fclose(f);
- f = NULL;
-
/* To avoid racing against processes which fork
* quicker than we can kill them we repeat this until
* no new pids need to be killed. */
} while (!done);
-finish:
- if (allocated_set)
- set_free(allocated_set);
-
- if (f)
- fclose(f);
-
return ret;
}
int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
+ _cleanup_set_free_ Set *allocated_set = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
int r, ret = 0;
- DIR *d = NULL;
char *fn;
- Set *allocated_set = NULL;
assert(path);
- assert(controller);
assert(sig >= 0);
- if (!s)
- if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
+ if (!s) {
+ s = allocated_set = set_new(trivial_hash_func, trivial_compare_func);
+ if (!s)
return -ENOMEM;
+ }
ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
- if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) {
+ r = cg_enumerate_subgroups(controller, path, &d);
+ if (r < 0) {
if (ret >= 0 && r != -ENOENT)
- ret = r;
+ return r;
- goto finish;
+ return ret;
}
while ((r = cg_read_subgroup(d, &fn)) > 0) {
- char *p = NULL;
+ _cleanup_free_ char *p = NULL;
- r = asprintf(&p, "%s/%s", path, fn);
+ p = strjoin(path, "/", fn, NULL);
free(fn);
-
- if (r < 0) {
- if (ret >= 0)
- ret = -ENOMEM;
-
- goto finish;
- }
+ if (!p)
+ return -ENOMEM;
r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
- free(p);
-
- if (r != 0 && ret >= 0)
+ if (ret >= 0 && r != 0)
ret = r;
}
- if (r < 0 && ret >= 0)
+ if (ret >= 0 && r < 0)
ret = r;
- if (rem)
- if ((r = cg_rmdir(controller, path, true)) < 0) {
- if (ret >= 0 &&
- r != -ENOENT &&
- r != -EBUSY)
- ret = r;
- }
-
-finish:
- if (d)
- closedir(d);
-
- if (allocated_set)
- set_free(allocated_set);
+ if (rem) {
+ r = cg_rmdir(controller, path, true);
+ if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
+ return r;
+ }
return ret;
}
@@ -349,7 +316,6 @@ int cg_kill_recursive_and_wait(const char *controller, const char *path, bool re
unsigned i;
assert(path);
- assert(controller);
/* This safely kills all processes; first it sends a SIGTERM,
* then checks 8 times after 200ms whether the group is now
@@ -367,7 +333,8 @@ int cg_kill_recursive_and_wait(const char *controller, const char *path, bool re
else
sig = 0;
- if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0)
+ r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL);
+ if (r <= 0)
return r;
usleep(200 * USEC_PER_MSEC);
@@ -381,7 +348,6 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
_cleanup_set_free_ Set *s = NULL;
int r, ret = 0;
pid_t my_pid;
- _cleanup_fclose_ FILE *f = NULL;
assert(cfrom);
assert(pfrom);
@@ -395,13 +361,14 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
my_pid = getpid();
do {
+ _cleanup_fclose_ FILE *f = NULL;
pid_t pid = 0;
done = true;
r = cg_enumerate_tasks(cfrom, pfrom, &f);
if (r < 0) {
if (ret >= 0 && r != -ENOENT)
- ret = r;
+ return r;
return ret;
}
@@ -411,7 +378,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
/* This might do weird stuff if we aren't a
* single-threaded program. However, we
* luckily know we are not */
- if (pid == my_pid && ignore_self)
+ if (ignore_self && pid == my_pid)
continue;
if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
@@ -429,7 +396,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
r = set_put(s, LONG_TO_PTR(pid));
if (r < 0) {
if (ret >= 0)
- ret = r;
+ return r;
return ret;
}
@@ -437,21 +404,18 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
if (r < 0) {
if (ret >= 0)
- ret = r;
+ return r;
return ret;
}
-
- fclose(f);
- f = NULL;
} while (!done);
return ret;
}
int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem) {
- int r, ret = 0;
_cleanup_closedir_ DIR *d = NULL;
+ int r, ret = 0;
char *fn;
assert(cfrom);
@@ -464,7 +428,8 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
r = cg_enumerate_subgroups(cfrom, pfrom, &d);
if (r < 0) {
if (ret >= 0 && r != -ENOENT)
- ret = r;
+ return r;
+
return ret;
}
@@ -475,7 +440,7 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
free(fn);
if (!p) {
if (ret >= 0)
- ret = -ENOMEM;
+ return -ENOMEM;
return ret;
}
@@ -499,6 +464,8 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
static const char *normalize_controller(const char *controller) {
+ assert(controller);
+
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
return "systemd";
else if (startswith(controller, "name="))
@@ -510,9 +477,6 @@ static const char *normalize_controller(const char *controller) {
static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
char *t = NULL;
- if (!(controller || path))
- return -EINVAL;
-
if (controller) {
if (path && suffix)
t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
@@ -521,12 +485,14 @@ static int join_path(const char *controller, const char *path, const char *suffi
else if (suffix)
t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
else
- t = strjoin("/sys/fs/cgroup/", controller, NULL);
+ t = strappend("/sys/fs/cgroup/", controller);
} else {
if (path && suffix)
t = strjoin(path, "/", suffix, NULL);
else if (path)
t = strdup(path);
+ else
+ return -EINVAL;
}
if (!t)
@@ -556,10 +522,11 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
}
p = controller ? normalize_controller(controller) : NULL;
+
return join_path(p, path, suffix, fs);
}
-static int check(const char *p) {
+static int check_hierarchy(const char *p) {
char *cc;
assert(p);
@@ -577,7 +544,6 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
const char *p;
int r;
- assert(controller);
assert(fs);
if (isempty(controller))
@@ -587,7 +553,7 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
p = normalize_controller(controller);
/* Check if this controller actually really exists */
- r = check(p);
+ r = check_hierarchy(p);
if (r < 0)
return r;
@@ -621,10 +587,9 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
}
int cg_trim(const char *controller, const char *path, bool delete_root) {
- char *fs;
+ _cleanup_free_ char *fs = NULL;
int r = 0;
- assert(controller);
assert(path);
r = cg_get_path(controller, path, NULL, &fs);
@@ -632,7 +597,7 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
return r;
errno = 0;
- if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
+ if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
r = errno ? -errno : -EIO;
if (delete_root) {
@@ -640,39 +605,31 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
char *p;
p = strappend(fs, "/tasks");
- if (!p) {
- free(fs);
+ if (!p)
return -ENOMEM;
- }
is_sticky = file_is_priv_sticky(p) > 0;
free(p);
if (!is_sticky)
- if (rmdir(fs) < 0 && errno != ENOENT) {
- if (r == 0)
- r = -errno;
- }
+ if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
+ return -errno;
}
- free(fs);
-
return r;
}
int cg_delete(const char *controller, const char *path) {
- char *parent;
+ _cleanup_free_ char *parent = NULL;
int r;
- assert(controller);
assert(path);
- if ((r = path_get_parent(path, &parent)) < 0)
+ r = path_get_parent(path, &parent);
+ if (r < 0)
return r;
r = cg_migrate_recursive(controller, path, controller, parent, false, true);
- free(parent);
-
return r == -ENOENT ? 0 : r;
}
@@ -681,7 +638,6 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
char c[DECIMAL_STR_MAX(pid_t) + 2];
int r;
- assert(controller);
assert(path);
assert(pid >= 0);
@@ -707,7 +663,6 @@ int cg_set_group_access(
_cleanup_free_ char *fs = NULL;
int r;
- assert(controller);
assert(path);
if (mode != (mode_t) -1)
@@ -731,7 +686,6 @@ int cg_set_task_access(
_cleanup_free_ char *fs = NULL, *procs = NULL;
int r;
- assert(controller);
assert(path);
if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
@@ -778,47 +732,35 @@ int cg_set_task_access(
return chmod_and_chown(procs, mode, uid, gid);
}
-int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
- int r;
- char *p = NULL;
- FILE *f;
- char *fs;
+int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
+ char fs[sizeof("/proc/") - 1 + DECIMAL_STR_MAX(pid_t) + sizeof("/cgroup")];
+ _cleanup_fclose_ FILE *f = NULL;
+ char line[LINE_MAX];
size_t cs;
- assert(controller);
assert(path);
assert(pid >= 0);
+ if (!controller)
+ controller = SYSTEMD_CGROUP_CONTROLLER;
+
if (pid == 0)
pid = getpid();
- if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
- return -ENOMEM;
-
+ sprintf(fs, "/proc/%lu/cgroup", (unsigned long) pid);
f = fopen(fs, "re");
- free(fs);
-
if (!f)
return errno == ENOENT ? -ESRCH : -errno;
cs = strlen(controller);
- while (!feof(f)) {
- char line[LINE_MAX];
- char *l;
-
- errno = 0;
- if (!(fgets(line, sizeof(line), f))) {
- if (feof(f))
- break;
-
- r = errno ? -errno : -EIO;
- goto finish;
- }
+ FOREACH_LINE(line, f, return -errno) {
+ char *l, *p;
truncate_nl(line);
- if (!(l = strchr(line, ':')))
+ l = strchr(line, ':');
+ if (!l)
continue;
l++;
@@ -828,90 +770,72 @@ int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
if (l[cs] != ':')
continue;
- if (!(p = strdup(l + cs + 1))) {
- r = -ENOMEM;
- goto finish;
- }
+ p = strdup(l + cs + 1);
+ if (!p)
+ return -ENOMEM;
*path = p;
- r = 0;
- goto finish;
+ return 0;
}
- r = -ENOENT;
-
-finish:
- fclose(f);
-
- return r;
+ return -ENOENT;
}
int cg_install_release_agent(const char *controller, const char *agent) {
- char *fs = NULL, *contents = NULL, *line = NULL, *sc;
+ _cleanup_free_ char *fs = NULL, *contents = NULL;
+ char *sc;
int r;
- assert(controller);
assert(agent);
- if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
+ r = cg_get_path(controller, NULL, "release_agent", &fs);
+ if (r < 0)
return r;
- if ((r = read_one_line_file(fs, &contents)) < 0)
- goto finish;
+ r = read_one_line_file(fs, &contents);
+ if (r < 0)
+ return r;
sc = strstrip(contents);
if (sc[0] == 0) {
-
- if (asprintf(&line, "%s\n", agent) < 0) {
- r = -ENOMEM;
- goto finish;
- }
-
- r = write_string_file(fs, line);
+ r = write_string_file(fs, agent);
if (r < 0)
- goto finish;
-
- } else if (!streq(sc, agent)) {
- r = -EEXIST;
- goto finish;
- }
+ return r;
+ } else if (!streq(sc, agent))
+ return -EEXIST;
free(fs);
fs = NULL;
- if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0)
- goto finish;
+ r = cg_get_path(controller, NULL, "notify_on_release", &fs);
+ if (r < 0)
+ return r;
free(contents);
contents = NULL;
- if ((r = read_one_line_file(fs, &contents)) < 0)
- goto finish;
+ r = read_one_line_file(fs, &contents);
+ if (r < 0)
+ return r;
sc = strstrip(contents);
-
if (streq(sc, "0")) {
- if ((r = write_string_file(fs, "1\n")) < 0)
- goto finish;
+ r = write_string_file(fs, "1");
+ if (r < 0)
+ return r;
- r = 1;
- } else if (!streq(sc, "1")) {
- r = -EIO;
- goto finish;
- } else
- r = 0;
+ return 1;
+ }
-finish:
- free(fs);
- free(contents);
- free(line);
+ if (!streq(sc, "1"))
+ return -EIO;
- return r;
+ return 0;
}
int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
+ _cleanup_fclose_ FILE *f = NULL;
pid_t pid = 0, self_pid;
- int r;
- FILE *f = NULL;
bool found = false;
+ int r;
assert(path);
@@ -930,8 +854,6 @@ int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
break;
}
- fclose(f);
-
if (r < 0)
return r;
@@ -939,8 +861,8 @@ 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 r;
_cleanup_free_ char *controller = NULL, *path = NULL;
+ int r;
assert(spec);
@@ -952,9 +874,9 @@ 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 r;
- DIR *d = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
char *fn;
+ int r;
assert(path);
@@ -967,32 +889,22 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
return r == -ENOENT ? 1 : r;
while ((r = cg_read_subgroup(d, &fn)) > 0) {
- char *p = NULL;
+ _cleanup_free_ char *p = NULL;
- r = asprintf(&p, "%s/%s", path, fn);
+ p = strjoin(path, "/", fn, NULL);
free(fn);
-
- if (r < 0) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!p)
+ return -ENOMEM;
r = cg_is_empty_recursive(controller, p, ignore_self);
- free(p);
-
if (r <= 0)
- goto finish;
+ return r;
}
- if (r >= 0)
- r = 1;
-
-finish:
-
- if (d)
- closedir(d);
+ if (r < 0)
+ return r;
- return r;
+ return 1;
}
int cg_split_spec(const char *spec, char **controller, char **path) {
@@ -1071,22 +983,31 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
}
int cg_join_spec(const char *controller, const char *path, char **spec) {
- assert(controller);
+ char *s;
+
assert(path);
- if (!path_is_absolute(path) ||
- controller[0] == 0 ||
- strchr(controller, ':') ||
- strchr(controller, '/'))
+ if (!controller)
+ controller = "systemd";
+ else if (controller[0] == 0 ||
+ strchr(controller, ':') ||
+ strchr(controller, '/'))
return -EINVAL;
- if (asprintf(spec, "%s:%s", controller, path) < 0)
+ if (!path_is_absolute(path))
+ return -EINVAL;
+
+ controller = normalize_controller(controller);
+
+ s = strjoin(controller, ":", path, NULL);
+ if (!s)
return -ENOMEM;
+ *spec = s;
return 0;
}
-int cg_fix_path(const char *path, char **result) {
+int cg_mangle_path(const char *path, char **result) {
char *t, *c, *p;
int r;
@@ -1094,8 +1015,7 @@ int cg_fix_path(const char *path, char **result) {
assert(result);
/* First check if it already is a filesystem path */
- if (path_startswith(path, "/sys/fs/cgroup") &&
- access(path, F_OK) >= 0) {
+ if (path_startswith(path, "/sys/fs/cgroup")) {
t = strdup(path);
if (!t)
@@ -1117,8 +1037,58 @@ int cg_fix_path(const char *path, char **result) {
return r;
}
+int cg_get_system_path(char **path) {
+ char *p;
+ int r;
+
+ assert(path);
+
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
+ if (r < 0) {
+ p = strdup("/system");
+ if (!p)
+ return -ENOMEM;
+ }
+
+ if (endswith(p, "/system"))
+ *path = p;
+ else {
+ char *q;
+
+ q = strappend(p, "/system");
+ free(p);
+ if (!q)
+ return -ENOMEM;
+
+ *path = q;
+ }
+
+ return 0;
+}
+
+int cg_get_root_path(char **path) {
+ char *root, *e;
+ int r;
+
+ assert(path);
+
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &root);
+ if (r < 0)
+ return r;
+
+ e = endswith(root, "/system");
+ if (e == root)
+ e[1] = 0;
+ else if (e)
+ *e = 0;
+
+ *path = root;
+ return 0;
+}
+
int cg_get_user_path(char **path) {
- char *root, *p;
+ _cleanup_free_ char *root = NULL;
+ char *p;
assert(path);
@@ -1126,17 +1096,28 @@ int cg_get_user_path(char **path) {
* same as PID 1 has but with the "/system" suffix replaced by
* "/user" */
- if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
+ if (cg_get_root_path(&root) < 0 || streq(root, "/"))
p = strdup("/user");
- else {
- if (endswith(root, "/system"))
- root[strlen(root) - 7] = 0;
- else if (streq(root, "/"))
- root[0] = 0;
-
+ else
p = strappend(root, "/user");
- free(root);
- }
+
+ if (!p)
+ return -ENOMEM;
+
+ *path = p;
+ return 0;
+}
+
+int cg_get_machine_path(char **path) {
+ _cleanup_free_ char *root = NULL;
+ char *p;
+
+ assert(path);
+
+ if (cg_get_root_path(&root) < 0 || streq(root, "/"))
+ p = strdup("/machine");
+ else
+ p = strappend(root, "/machine");
if (!p)
return -ENOMEM;
@@ -1152,17 +1133,17 @@ char **cg_shorten_controllers(char **controllers) {
return controllers;
for (f = controllers, t = controllers; *f; f++) {
- int r;
const char *p;
+ int r;
+
+ p = normalize_controller(*f);
- if (streq(*f, "systemd") || streq(*f, SYSTEMD_CGROUP_CONTROLLER)) {
+ if (streq(*f, "systemd")) {
free(*f);
continue;
}
- p = normalize_controller(*f);
-
- r = check(p);
+ r = check_hierarchy(p);
if (r < 0) {
log_debug("Controller %s is not available, removing from controllers list.", *f);
free(*f);
@@ -1176,33 +1157,24 @@ char **cg_shorten_controllers(char **controllers) {
return strv_uniq(controllers);
}
-int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) {
- char *cg_process, *cg_init, *p, *q;
+int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) {
+ _cleanup_free_ char *cg_root = NULL;
+ char *cg_process, *p;
int r;
- assert(pid >= 0);
-
- if (pid == 0)
- pid = getpid();
-
- r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
+ r = cg_get_root_path(&cg_root);
if (r < 0)
return r;
- r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init);
- if (r < 0) {
- free(cg_process);
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
+ if (r < 0)
return r;
- }
-
- if (endswith(cg_init, "/system"))
- cg_init[strlen(cg_init)-7] = 0;
- else if (streq(cg_init, "/"))
- cg_init[0] = 0;
- q = startswith(cg_process, cg_init);
- p = q ? q : cg_process;
- free(cg_init);
+ p = path_startswith(cg_process, cg_root);
+ if (p)
+ p--;
+ else
+ p = cg_process;
if (cgroup) {
char* c;
@@ -1226,7 +1198,7 @@ int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) {
}
/* non-static only for testing purposes */
-int cg_cgroup_to_unit(const char *cgroup, char **unit){
+int cg_path_decode_unit(const char *cgroup, char **unit){
char *p, *e, *c, *s, *k;
assert(cgroup);
@@ -1274,7 +1246,7 @@ int cg_path_get_unit(const char *path, char **unit) {
if (!e)
return -ENOENT;
- return cg_cgroup_to_unit(e, unit);
+ return cg_path_decode_unit(e, unit);
}
int cg_pid_get_unit(pid_t pid, char **unit) {
@@ -1283,7 +1255,7 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
assert(unit);
- r = cg_pid_get_cgroup(pid, NULL, &cgroup);
+ r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
if (r < 0)
return r;
@@ -1293,7 +1265,6 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
static const char *skip_label(const char *e) {
assert(e);
- e += strspn(e, "/");
e = strchr(e, '/');
if (!e)
return NULL;
@@ -1331,7 +1302,7 @@ int cg_path_get_user_unit(const char *path, char **unit) {
if (!e)
return -ENOENT;
- return cg_cgroup_to_unit(e, unit);
+ return cg_path_decode_unit(e, unit);
}
int cg_pid_get_user_unit(pid_t pid, char **unit) {
@@ -1340,13 +1311,93 @@ int cg_pid_get_user_unit(pid_t pid, char **unit) {
assert(unit);
- r = cg_pid_get_cgroup(pid, NULL, &cgroup);
+ r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
if (r < 0)
return r;
return cg_path_get_user_unit(cgroup, unit);
}
+int cg_path_get_machine_name(const char *path, char **machine) {
+ const char *e, *n;
+ char *s;
+
+ assert(path);
+ assert(machine);
+
+ e = path_startswith(path, "/machine/");
+ if (!e)
+ return -ENOENT;
+
+ n = strchrnul(e, '/');
+ if (e == n)
+ return -ENOENT;
+
+ s = strndup(e, n - e);
+ if (!s)
+ return -ENOMEM;
+
+ *machine = s;
+ return 0;
+}
+
+int cg_pid_get_machine_name(pid_t pid, char **machine) {
+ char _cleanup_free_ *cgroup = NULL;
+ int r;
+
+ assert(machine);
+
+ r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
+ if (r < 0)
+ return r;
+
+ return cg_path_get_machine_name(cgroup, machine);
+}
+
+int cg_path_get_session(const char *path, char **session) {
+ const char *e, *n;
+ char *s;
+
+ assert(path);
+ assert(session);
+
+ e = path_startswith(path, "/user/");
+ if (!e)
+ return -ENOENT;
+
+ /* Skip the user name */
+ e = skip_label(e);
+ if (!e)
+ return -ENOENT;
+
+ n = strchrnul(e, '/');
+ if (e == n)
+ return -ENOENT;
+
+ if (n - e == 6 && memcmp(e, "shared", 6) == 0)
+ return -ENOENT;
+
+ s = strndup(e, n - e);
+ if (!s)
+ return -ENOMEM;
+
+ *session = s;
+ return 0;
+}
+
+int cg_pid_get_session(pid_t pid, char **session) {
+ char _cleanup_free_ *cgroup = NULL;
+ int r;
+
+ assert(session);
+
+ r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
+ if (r < 0)
+ return r;
+
+ return cg_path_get_session(cgroup, session);
+}
+
int cg_controller_from_attr(const char *attr, char **controller) {
const char *dot;
char *c;
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index 274380aa2d..5457d1bcaa 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -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_path_shifted(pid_t pid, char **root, char **cgroup);
-int cg_pid_get_cgroup(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);
diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h
index 11282b7611..1083742beb 100644
--- a/src/systemd/sd-login.h
+++ b/src/systemd/sd-login.h
@@ -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);
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 8e24d1ceca..5eaa129418 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -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;
}
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
index 2f7cc9be0a..3a3489d6a2 100644
--- a/src/test/test-cgroup.c
+++ b/src/test/test-cgroup.c
@@ -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);
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 2d9093d741..7d13b4f532 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -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 */