cgls: beef up control group dumping and introduce cgls tool
This commit is contained in:
+150
-22
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user