cgls: beef up control group dumping and introduce cgls tool

This commit is contained in:
Lennart Poettering
2010-07-08 21:01:42 +02:00
parent ab35fb1bc6
commit fa776d8e96
9 changed files with 424 additions and 50 deletions
+150 -22
View File
@@ -21,6 +21,8 @@
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include "util.h"
#include "macro.h"
@@ -36,25 +38,57 @@ static int compare(const void *a, const void *b) {
return 0;
}
void show_cgroup(const char *name, const char *prefix, unsigned columns) {
static char *get_cgroup_path(const char *name) {
if (startswith(name, "name=systemd:"))
name += 13;
if (path_startswith(name, "/cgroup"))
return strdup(name);
return strappend("/cgroup/systemd/", name);
}
static unsigned ilog10(unsigned long ul) {
int n = 0;
while (ul > 0) {
n++;
ul /= 10;
}
return n;
}
static int show_cgroup_full(const char *name, const char *prefix, unsigned n_columns, bool more) {
char *fn;
FILE *f;
size_t n = 0, n_allocated = 0;
pid_t *pids = NULL;
char *p;
int r;
unsigned long biggest = 0;
if (!startswith(name, "name=systemd:"))
return;
if (n_columns <= 0)
n_columns = columns();
if (asprintf(&fn, "/cgroup/systemd/%s/cgroup.procs", name + 13) < 0) {
log_error("Out of memory");
return;
}
if (!prefix)
prefix = "";
f = fopen(fn, "r");
if (!(p = get_cgroup_path(name)))
return -ENOMEM;
r = asprintf(&fn, "%s/cgroup.procs", p);
free(p);
if (r < 0)
return -ENOMEM;
f = fopen(fn, "re");
free(fn);
if (!f)
return;
return -errno;
while (!feof(f)) {
unsigned long ul;
@@ -71,7 +105,7 @@ void show_cgroup(const char *name, const char *prefix, unsigned columns) {
n_allocated = MAX(16U, n*2U);
if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
log_error("Out of memory");
r = -ENOMEM;
goto finish;
}
@@ -80,6 +114,9 @@ void show_cgroup(const char *name, const char *prefix, unsigned columns) {
assert(n < n_allocated);
pids[n++] = (pid_t) ul;
if (ul > biggest)
biggest = ul;
}
if (n > 0) {
@@ -102,33 +139,124 @@ void show_cgroup(const char *name, const char *prefix, unsigned columns) {
/* And sort */
qsort(pids, n, sizeof(pid_t), compare);
if (!prefix)
prefix = "";
if (columns > 8)
columns -= 8;
if (n_columns > 8)
n_columns -= 8;
else
columns = 20;
printf("%s\342\224\202\n", prefix);
n_columns = 20;
for (i = 0; i < n; i++) {
char *t = NULL;
get_process_cmdline(pids[i], columns, &t);
get_process_cmdline(pids[i], n_columns, &t);
printf("%s%s %5lu %s\n",
printf("%s%s %*lu %s\n",
prefix,
i < n-1 ? "\342\224\234" : "\342\224\224",
(unsigned long) pids[i], strna(t));
(more || i < n-1) ? "\342\224\234" : "\342\224\224",
ilog10(biggest),
(unsigned long) pids[i],
strna(t));
free(t);
}
}
r = 0;
finish:
free(pids);
if (f)
fclose(f);
return r;
}
int show_cgroup(const char *name, const char *prefix, unsigned n_columns) {
return show_cgroup_full(name, prefix, n_columns, false);
}
int show_cgroup_recursive(const char *name, const char *prefix, unsigned n_columns) {
DIR *d;
char *last = NULL;
char *p1 = NULL, *p2 = NULL, *fn = NULL;
struct dirent *de;
bool shown_pids = false;
int r;
assert(name);
if (n_columns <= 0)
n_columns = columns();
if (!prefix)
prefix = "";
if (!(fn = get_cgroup_path(name)))
return -ENOMEM;
if (!(d = opendir(fn))) {
free(fn);
return -errno;
}
while ((de = readdir(d))) {
if (de->d_type != DT_DIR)
continue;
if (ignore_file(de->d_name))
continue;
if (!shown_pids) {
show_cgroup_full(name, prefix, n_columns, true);
shown_pids = true;
}
if (last) {
printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
if (!p1)
if (!(p1 = strappend(prefix, "\342\224\202 "))) {
r = -ENOMEM;
goto finish;
}
show_cgroup_recursive(last, p1, n_columns-2);
free(last);
last = NULL;
}
if (asprintf(&last, "%s/%s", name, de->d_name) < 0) {
log_error("Out of memory");
goto finish;
}
}
if (!shown_pids)
show_cgroup_full(name, prefix, n_columns, !!last);
if (last) {
printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
if (!p2)
if (!(p2 = strappend(prefix, " "))) {
r = -ENOMEM;
goto finish;
}
show_cgroup_recursive(last, p2, n_columns-2);
}
r = 0;
finish:
free(p1);
free(p2);
free(last);
free(fn);
closedir(d);
return r;
}
+2 -1
View File
@@ -22,6 +22,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
void show_cgroup(const char *name, const char *prefix, unsigned columns);
int show_cgroup(const char *name, const char *prefix, unsigned columns);
int show_cgroup_recursive(const char *name, const char *prefix, unsigned columns);
#endif
+2 -26
View File
@@ -110,30 +110,6 @@ static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *da
return 0;
}
static int columns(void) {
static int parsed_columns = 0;
const char *e;
if (parsed_columns > 0)
return parsed_columns;
if ((e = getenv("COLUMNS")))
parsed_columns = atoi(e);
if (parsed_columns <= 0) {
struct winsize ws;
zero(ws);
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
parsed_columns = ws.ws_col;
}
if (parsed_columns <= 0)
parsed_columns = 80;
return parsed_columns;
}
static void warn_wall(enum action action) {
static const char *table[_ACTION_MAX] = {
[ACTION_HALT] = "The system is going down for system halt NOW!",
@@ -1076,7 +1052,7 @@ static void print_status_info(UnitStatusInfo *i) {
else
c = 0;
show_cgroup(i->default_control_group, "\t\t ", c);
show_cgroup_recursive(i->default_control_group, "\t\t ", c);
}
}
@@ -3068,7 +3044,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
{ "reboot", EQUAL, 1, start_special },
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special }
};
int left;
+121
View File
@@ -0,0 +1,121 @@
/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <string.h>
#include "cgroup-show.h"
#include "log.h"
#include "util.h"
static void help(void) {
printf("%s [OPTIONS...] [CGROUP...]\n\n"
"Recursively show control group contents.\n\n"
" -h --help Show this help\n",
program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 1);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case '?':
return -EINVAL;
default:
log_error("Unknown option code %c", c);
return -EINVAL;
}
}
return 1;
}
int main(int argc, char *argv[]) {
int r = 0, retval = 1;
log_parse_environment();
if ((r = parse_argv(argc, argv)) < 0)
goto finish;
else if (r == 0) {
retval = 0;
goto finish;
}
if (optind < argc) {
unsigned i;
for (i = (unsigned) optind; i < (unsigned) argc; i++) {
int q;
printf("%s:\n", argv[i]);
if ((q = show_cgroup_recursive(argv[i], NULL, 0)) < 0)
r = q;
}
} else {
char *p;
if (!(p = get_current_dir_name())) {
log_error("Cannot determine current working directory: %m");
goto finish;
}
if (path_startswith(p, "/cgroup")) {
printf("Working Directory %s:\n", p);
r = show_cgroup_recursive(p, NULL, 0);
} else
r = show_cgroup_recursive("", NULL, 0);
free(p);
}
if (r < 0)
log_error("Failed to list cgroup tree: %s", strerror(-r));
retval = 0;
finish:
return retval;
}
+27
View File
@@ -609,6 +609,9 @@ int get_process_cmdline(pid_t pid, size_t max_length, char **line) {
fclose(f);
if (r[0] == 0)
return get_process_name(pid, line);
*line = r;
return 0;
}
@@ -2798,6 +2801,30 @@ char **replace_env_argv(char **argv, char **env) {
return r;
}
int columns(void) {
static __thread int parsed_columns = 0;
const char *e;
if (parsed_columns > 0)
return parsed_columns;
if ((e = getenv("COLUMNS")))
parsed_columns = atoi(e);
if (parsed_columns <= 0) {
struct winsize ws;
zero(ws);
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
parsed_columns = ws.ws_col;
}
if (parsed_columns <= 0)
parsed_columns = 80;
return parsed_columns;
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
+2
View File
@@ -328,6 +328,8 @@ void status_vprintf(const char *format, va_list ap);
void status_printf(const char *format, ...);
void status_welcome(void);
int columns(void);
const char *ioprio_class_to_string(int i);
int ioprio_class_from_string(const char *s);