cgls: don't show empty cgroups by default

This commit is contained in:
Lennart Poettering 2012-04-16 17:35:58 +02:00
parent c7b5eb98e8
commit c3175a7f40
8 changed files with 115 additions and 57 deletions

2
TODO
View File

@ -15,6 +15,8 @@ Bugfixes:
Features: Features:
* suspend/hibernate/hybrid support, auto-suspend logic with idle hint
* filter default cgroups in logind too * filter default cgroups in logind too
* remove empty cgroups from cgls output * remove empty cgroups from cgls output

View File

@ -69,6 +69,9 @@
of the control group the working directory refers of the control group the working directory refers
to. Otherwise the full systemd control group hierarchy to. Otherwise the full systemd control group hierarchy
is shown.</para> is shown.</para>
<para>By default empty control cgroups are not
shown.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
@ -85,6 +88,13 @@
text and exits.</para></listitem> text and exits.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--version</option></term>
<listitem><para>Prints a short version
string and exits.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--no-pager</option></term> <term><option>--no-pager</option></term>
@ -92,6 +102,14 @@
pager.</para></listitem> pager.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--all</option></term>
<listitem><para>Don't hide empty
control groups in the
outpout.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-k</option></term> <term><option>-k</option></term>

View File

@ -31,16 +31,20 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#include "pager.h" #include "pager.h"
#include "build.h"
static bool arg_no_pager = false; static bool arg_no_pager = false;
static bool arg_kernel_threads = false; static bool arg_kernel_threads = false;
static bool arg_all = false;
static void help(void) { static void help(void) {
printf("%s [OPTIONS...] [CGROUP...]\n\n" printf("%s [OPTIONS...] [CGROUP...]\n\n"
"Recursively show control group contents.\n\n" "Recursively show control group contents.\n\n"
" -h --help Show this help\n" " -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n" " --no-pager Do not pipe output into a pager\n"
" -a --all Show all groups, including empty\n"
" -k Include kernel threads in output\n", " -k Include kernel threads in output\n",
program_invocation_short_name); program_invocation_short_name);
} }
@ -48,12 +52,15 @@ static void help(void) {
static int parse_argv(int argc, char *argv[]) { static int parse_argv(int argc, char *argv[]) {
enum { enum {
ARG_NO_PAGER = 0x100 ARG_NO_PAGER = 0x100,
ARG_VERSION
}; };
static const struct option options[] = { static const struct option options[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "all", no_argument, NULL, 'a' },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
@ -62,7 +69,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1); assert(argc >= 1);
assert(argv); assert(argv);
while ((c = getopt_long(argc, argv, "hk", options, NULL)) >= 0) { while ((c = getopt_long(argc, argv, "hka", options, NULL)) >= 0) {
switch (c) { switch (c) {
@ -70,10 +77,20 @@ static int parse_argv(int argc, char *argv[]) {
help(); help();
return 0; return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(DISTRIBUTION);
puts(SYSTEMD_FEATURES);
return 0;
case ARG_NO_PAGER: case ARG_NO_PAGER:
arg_no_pager = true; arg_no_pager = true;
break; break;
case 'a':
arg_all = true;
break;
case 'k': case 'k':
arg_kernel_threads = true; arg_kernel_threads = true;
break; break;
@ -114,7 +131,7 @@ int main(int argc, char *argv[]) {
int q; int q;
printf("%s:\n", argv[i]); printf("%s:\n", argv[i]);
q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads); q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, arg_all);
if (q < 0) if (q < 0)
r = q; r = q;
} }
@ -130,7 +147,7 @@ int main(int argc, char *argv[]) {
if (path_startswith(p, "/sys/fs/cgroup")) { if (path_startswith(p, "/sys/fs/cgroup")) {
printf("Working Directory %s:\n", p); printf("Working Directory %s:\n", p);
r = show_cgroup_by_path(p, NULL, 0, arg_kernel_threads); r = show_cgroup_by_path(p, NULL, 0, arg_kernel_threads, arg_all);
} else { } else {
char *root = NULL; char *root = NULL;
const char *t = NULL; const char *t = NULL;
@ -145,7 +162,7 @@ int main(int argc, char *argv[]) {
t = root[0] ? root : "/"; t = root[0] ? root : "/";
} }
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0, arg_kernel_threads); r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0, arg_kernel_threads, arg_all);
free(root); free(root);
} }

View File

@ -473,7 +473,7 @@ static void print_session_status_info(SessionStatusInfo *i) {
else else
c = 0; c = 0;
show_cgroup_by_path(i->control_group, "\t\t ", c, false); show_cgroup_by_path(i->control_group, "\t\t ", c, false, arg_all);
} }
} }
} }
@ -525,7 +525,7 @@ static void print_user_status_info(UserStatusInfo *i) {
else else
c = 0; c = 0;
show_cgroup_by_path(i->control_group, "\t\t ", c, false); show_cgroup_by_path(i->control_group, "\t\t ", c, false, arg_all);
} }
} }
} }

View File

@ -160,7 +160,7 @@ finish:
return r; return r;
} }
int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) { int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
DIR *d; DIR *d;
char *last = NULL; char *last = NULL;
char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL; char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
@ -173,15 +173,31 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (!prefix) if (!prefix)
prefix = ""; prefix = "";
if ((r = cg_fix_path(path, &fn)) < 0) r = cg_fix_path(path, &fn);
if (r < 0)
return r; return r;
if (!(d = opendir(fn))) { d = opendir(fn);
if (!d) {
free(fn); free(fn);
return -errno; return -errno;
} }
while ((r = cg_read_subgroup(d, &gn)) > 0) { while ((r = cg_read_subgroup(d, &gn)) > 0) {
char *k;
r = asprintf(&k, "%s/%s", fn, gn);
free(gn);
if (r < 0) {
r = -ENOMEM;
goto finish;
}
if (!all && cg_is_empty_recursive(NULL, k, false) > 0) {
free(k);
continue;
}
if (!shown_pids) { if (!shown_pids) {
show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads); show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
@ -191,25 +207,20 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (last) { if (last) {
printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last)); printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
if (!p1) if (!p1) {
if (!(p1 = strappend(prefix, "\342\224\202 "))) { p1 = strappend(prefix, "\342\224\202 ");
if (!p1) {
free(k);
r = -ENOMEM; r = -ENOMEM;
goto finish; goto finish;
} }
}
show_cgroup_by_path(last, p1, n_columns-2, kernel_threads); show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, all);
free(last); free(last);
last = NULL;
} }
r = asprintf(&last, "%s/%s", fn, gn); last = k;
free(gn);
if (r < 0) {
r = -ENOMEM;
goto finish;
}
} }
if (r < 0) if (r < 0)
@ -221,13 +232,15 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (last) { if (last) {
printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last)); printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
if (!p2) if (!p2) {
if (!(p2 = strappend(prefix, " "))) { p2 = strappend(prefix, " ");
if (!p2) {
r = -ENOMEM; r = -ENOMEM;
goto finish; goto finish;
} }
}
show_cgroup_by_path(last, p2, n_columns-2, kernel_threads); show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, all);
} }
r = 0; r = 0;
@ -243,7 +256,7 @@ finish:
return r; return r;
} }
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) { int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) {
char *p; char *p;
int r; int r;
@ -254,7 +267,7 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
if (r < 0) if (r < 0)
return r; return r;
r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads); r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, all);
free(p); free(p);
return r; return r;

View File

@ -24,7 +24,7 @@
#include <stdbool.h> #include <stdbool.h>
int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads); int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all);
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads); int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all);
#endif #endif

View File

@ -40,11 +40,11 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **_f)
int r; int r;
FILE *f; FILE *f;
assert(controller);
assert(path); assert(path);
assert(_f); assert(_f);
if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0) r = cg_get_path(controller, path, "cgroup.procs", &fs);
if (r < 0)
return r; return r;
f = fopen(fs, "re"); f = fopen(fs, "re");
@ -62,11 +62,11 @@ int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
int r; int r;
FILE *f; FILE *f;
assert(controller);
assert(path); assert(path);
assert(_f); assert(_f);
if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0) r = cg_get_path(controller, path, "tasks", &fs);
if (r < 0)
return r; return r;
f = fopen(fs, "re"); f = fopen(fs, "re");
@ -106,13 +106,13 @@ int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
int r; int r;
DIR *d; DIR *d;
assert(controller);
assert(path); assert(path);
assert(_d); assert(_d);
/* This is not recursive! */ /* This is not recursive! */
if ((r = cg_get_path(controller, path, NULL, &fs)) < 0) r = cg_get_path(controller, path, NULL, &fs);
if (r < 0)
return r; return r;
d = opendir(fs); d = opendir(fs);
@ -515,14 +515,24 @@ static const char *normalize_controller(const char *controller) {
static int join_path(const char *controller, const char *path, const char *suffix, char **fs) { static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
char *t; char *t;
if (path && suffix) if (!(controller || path))
t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL); return -EINVAL;
else if (path)
t = join("/sys/fs/cgroup/", controller, "/", path, NULL); if (controller) {
else if (suffix) if (path && suffix)
t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL); t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
else else if (path)
t = join("/sys/fs/cgroup/", controller, NULL); t = join("/sys/fs/cgroup/", controller, "/", path, NULL);
else if (suffix)
t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL);
else
t = join("/sys/fs/cgroup/", controller, NULL);
} else {
if (path && suffix)
t = join(path, "/", suffix, NULL);
else if (path)
t = strdup(path);
}
if (!t) if (!t)
return -ENOMEM; return -ENOMEM;
@ -537,12 +547,8 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
const char *p; const char *p;
static __thread bool good = false; static __thread bool good = false;
assert(controller);
assert(fs); assert(fs);
if (isempty(controller))
return -EINVAL;
if (_unlikely_(!good)) { if (_unlikely_(!good)) {
int r; int r;
@ -554,8 +560,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
good = true; good = true;
} }
p = normalize_controller(controller); p = controller ? normalize_controller(controller) : NULL;
return join_path(p, path, suffix, fs); return join_path(p, path, suffix, fs);
} }
@ -883,20 +888,22 @@ finish:
} }
int cg_is_empty(const char *controller, const char *path, bool ignore_self) { int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
pid_t pid = 0; pid_t pid = 0, self_pid;
int r; int r;
FILE *f = NULL; FILE *f = NULL;
bool found = false; bool found = false;
assert(controller);
assert(path); assert(path);
if ((r = cg_enumerate_tasks(controller, path, &f)) < 0) r = cg_enumerate_tasks(controller, path, &f);
if (r < 0)
return r == -ENOENT ? 1 : r; return r == -ENOENT ? 1 : r;
self_pid = getpid();
while ((r = cg_read_pid(f, &pid)) > 0) { while ((r = cg_read_pid(f, &pid)) > 0) {
if (ignore_self && pid == getpid()) if (ignore_self && pid == self_pid)
continue; continue;
found = true; found = true;
@ -916,13 +923,14 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
DIR *d = NULL; DIR *d = NULL;
char *fn; char *fn;
assert(controller);
assert(path); assert(path);
if ((r = cg_is_empty(controller, path, ignore_self)) <= 0) r = cg_is_empty(controller, path, ignore_self);
if (r <= 0)
return r; return r;
if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) r = cg_enumerate_subgroups(controller, path, &d);
if (r < 0)
return r == -ENOENT ? 1 : r; return r == -ENOENT ? 1 : r;
while ((r = cg_read_subgroup(d, &fn)) > 0) { while ((r = cg_read_subgroup(d, &fn)) > 0) {

View File

@ -2383,7 +2383,7 @@ static void print_status_info(UnitStatusInfo *i) {
else else
c = 0; c = 0;
show_cgroup_by_path(i->default_control_group, "\t\t ", c, false); show_cgroup_by_path(i->default_control_group, "\t\t ", c, false, arg_all);
} }
} }