Merge pull request #1093 from poettering/unified-prepare
A variety of clean-ups
This commit is contained in:
commit
d728d7faa6
|
@ -165,15 +165,39 @@
|
|||
|
||||
<listitem><para>Controls whether the CPU usage is shown as
|
||||
percentage or time. By default the CPU usage is shown as
|
||||
percentage.</para></listitem>
|
||||
percentage. This setting may also be toggled at runtime by
|
||||
pressing the <keycap>%</keycap> key.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-k</option></term>
|
||||
|
||||
<listitem><para>Include kernel threads when counting tasks in
|
||||
control groups. By default, kernel threads are not included in
|
||||
the count. This setting may also be toggled at runtime by
|
||||
pressing the <keycap>k</keycap> key.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--recursive=</option></term>
|
||||
|
||||
<listitem><para>Controls whether the number of tasks shown for
|
||||
a control group shall include all tasks that are contained in
|
||||
any of the child control groups as well. Takes a boolean
|
||||
argument, defaults to <literal>yes</literal>. If enabled the
|
||||
tasks in child control groups are included, if disabled only
|
||||
the tasks in the control group itself are counted. This
|
||||
setting may also be toggled at runtime by pressing the
|
||||
<keycap>r</keycap> key.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-n</option></term>
|
||||
<term><option>--iterations=</option></term>
|
||||
|
||||
<listitem><para>Perform only this many iterations. A value of 0
|
||||
indicates that the program should run indefinitely.</para></listitem>
|
||||
<listitem><para>Perform only this many iterations. A value of
|
||||
0 indicates that the program should run
|
||||
indefinitely.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -181,10 +205,11 @@
|
|||
<term><option>--delay=</option></term>
|
||||
|
||||
<listitem><para>Specify refresh delay in seconds (or if one of
|
||||
<literal>ms</literal>,
|
||||
<literal>us</literal>,
|
||||
<literal>ms</literal>, <literal>us</literal>,
|
||||
<literal>min</literal> is specified as unit in this time
|
||||
unit).</para></listitem>
|
||||
unit). This setting may also be increased and decreased at
|
||||
runtime by pressing the <keycap>+</keycap> and
|
||||
<keycap>-</keycap> keys.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -204,7 +229,6 @@
|
|||
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>Keys</title>
|
||||
|
||||
|
@ -213,49 +237,72 @@
|
|||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>h</term>
|
||||
<term><keycap>h</keycap></term>
|
||||
|
||||
<listitem><para>Shows a short help text.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>SPACE</term>
|
||||
<term><keycap function="space"/></term>
|
||||
|
||||
<listitem><para>Immediately refresh output.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>q</term>
|
||||
<term><keycap>q</keycap></term>
|
||||
|
||||
<listitem><para>Terminate the program.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term>p</term>
|
||||
<term>t</term>
|
||||
<term>c</term>
|
||||
<term>m</term>
|
||||
<term>i</term>
|
||||
<term><keycap>p</keycap></term>
|
||||
<term><keycap>t</keycap></term>
|
||||
<term><keycap>c</keycap></term>
|
||||
<term><keycap>m</keycap></term>
|
||||
<term><keycap>i</keycap></term>
|
||||
|
||||
<listitem><para>Sort the control groups by path, number of
|
||||
tasks, CPU load, memory usage, or IO load, respectively.
|
||||
</para></listitem>
|
||||
tasks, CPU load, memory usage, or IO load, respectively. This
|
||||
setting may also be controlled using the
|
||||
<option>--order=</option> command line
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>%</term>
|
||||
<term><keycap>%</keycap></term>
|
||||
|
||||
<listitem><para>Toggle between showing CPU time as time or
|
||||
percentage.</para></listitem>
|
||||
percentage. This setting may also be controlled using the
|
||||
<option>--cpu=</option> command line switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>+</term>
|
||||
<term>-</term>
|
||||
<term><keycap>+</keycap></term>
|
||||
<term><keycap>-</keycap></term>
|
||||
|
||||
<listitem><para>Increase or decrease refresh delay,
|
||||
respectively.</para></listitem>
|
||||
respectively. This setting may also be controlled using the
|
||||
<option>--delay=</option> command line
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><keycap>k</keycap></term>
|
||||
|
||||
<listitem><para>Toggle between including or excluding kernel
|
||||
threads in control group task counts. This setting may also be
|
||||
controlled using the <option>-k</option> command line
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><keycap>r</keycap></term>
|
||||
|
||||
<listitem><para>Toggle between recursively including or
|
||||
excluding tasks in child control groups in control group task
|
||||
counts. This setting may also be controlled using the
|
||||
<option>--recursive=</option> command line
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
|
|
@ -181,10 +181,10 @@ int is_kernel_thread(pid_t pid) {
|
|||
bool eof;
|
||||
FILE *f;
|
||||
|
||||
if (pid == 0)
|
||||
if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */
|
||||
return 0;
|
||||
|
||||
assert(pid > 0);
|
||||
assert(pid > 1);
|
||||
|
||||
p = procfs_file_alloca(pid, "cmdline");
|
||||
f = fopen(p, "re");
|
||||
|
|
|
@ -4273,7 +4273,7 @@ bool is_locale_utf8(void) {
|
|||
/* Check result, but ignore the result if C was set
|
||||
* explicitly. */
|
||||
cached_answer =
|
||||
streq(set, "C") &&
|
||||
STR_IN_SET(set, "C", "POSIX") &&
|
||||
!getenv("LC_ALL") &&
|
||||
!getenv("LC_CTYPE") &&
|
||||
!getenv("LANG");
|
||||
|
|
|
@ -160,7 +160,7 @@ static int get_cgroup_root(char **ret) {
|
|||
&error,
|
||||
ret);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to query unit control group path: %m");
|
||||
return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ int main(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
printf("Control group %s:\n", root);
|
||||
printf("Control group %s:\n", isempty(root) ? "/" : root);
|
||||
fflush(stdout);
|
||||
|
||||
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "path-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "process-util.h"
|
||||
#include "util.h"
|
||||
#include "hashmap.h"
|
||||
#include "cgroup-util.h"
|
||||
|
@ -64,6 +65,8 @@ static unsigned arg_iterations = (unsigned) -1;
|
|||
static bool arg_batch = false;
|
||||
static bool arg_raw = false;
|
||||
static usec_t arg_delay = 1*USEC_PER_SEC;
|
||||
static bool arg_kernel_threads = false;
|
||||
static bool arg_recursive = true;
|
||||
|
||||
static enum {
|
||||
ORDER_PATH,
|
||||
|
@ -107,7 +110,14 @@ static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, off_t
|
|||
return format_bytes(buf, l, t);
|
||||
}
|
||||
|
||||
static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) {
|
||||
static int process(
|
||||
const char *controller,
|
||||
const char *path,
|
||||
Hashmap *a,
|
||||
Hashmap *b,
|
||||
unsigned iteration,
|
||||
Group **ret) {
|
||||
|
||||
Group *g;
|
||||
int r;
|
||||
|
||||
|
@ -154,8 +164,13 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap
|
|||
return r;
|
||||
|
||||
g->n_tasks = 0;
|
||||
while (cg_read_pid(f, &pid) > 0)
|
||||
while (cg_read_pid(f, &pid) > 0) {
|
||||
|
||||
if (!arg_kernel_threads && is_kernel_thread(pid) > 0)
|
||||
continue;
|
||||
|
||||
g->n_tasks++;
|
||||
}
|
||||
|
||||
if (g->n_tasks > 0)
|
||||
g->n_tasks_valid = true;
|
||||
|
@ -296,6 +311,9 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap
|
|||
g->io_iteration = iteration;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = g;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -305,9 +323,11 @@ static int refresh_one(
|
|||
Hashmap *a,
|
||||
Hashmap *b,
|
||||
unsigned iteration,
|
||||
unsigned depth) {
|
||||
unsigned depth,
|
||||
Group **ret) {
|
||||
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
Group *ours;
|
||||
int r;
|
||||
|
||||
assert(controller);
|
||||
|
@ -317,7 +337,7 @@ static int refresh_one(
|
|||
if (depth > arg_depth)
|
||||
return 0;
|
||||
|
||||
r = process(controller, path, a, b, iteration);
|
||||
r = process(controller, path, a, b, iteration, &ours);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -329,10 +349,13 @@ static int refresh_one(
|
|||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *fn = NULL, *p = NULL;
|
||||
Group *child = NULL;
|
||||
|
||||
r = cg_read_subgroup(d, &fn);
|
||||
if (r <= 0)
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
p = strjoin(path, "/", fn, NULL);
|
||||
if (!p)
|
||||
|
@ -340,29 +363,47 @@ static int refresh_one(
|
|||
|
||||
path_kill_slashes(p);
|
||||
|
||||
r = refresh_one(controller, p, a, b, iteration, depth + 1);
|
||||
r = refresh_one(controller, p, a, b, iteration, depth + 1, &child);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_recursive &&
|
||||
child &&
|
||||
child->n_tasks_valid &&
|
||||
streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
|
||||
/* Recursively sum up processes */
|
||||
|
||||
if (ours->n_tasks_valid)
|
||||
ours->n_tasks += child->n_tasks;
|
||||
else {
|
||||
ours->n_tasks = child->n_tasks;
|
||||
ours->n_tasks_valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
if (ret)
|
||||
*ret = ours;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) {
|
||||
static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
|
||||
r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, "/", a, b, iteration, 0);
|
||||
r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, root, a, b, iteration, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = refresh_one("cpuacct", "/", a, b, iteration, 0);
|
||||
r = refresh_one("cpuacct", root, a, b, iteration, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = refresh_one("memory", "/", a, b, iteration, 0);
|
||||
r = refresh_one("memory", root, a, b, iteration, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = refresh_one("blkio", "/", a, b, iteration, 0);
|
||||
r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -372,11 +413,11 @@ static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) {
|
|||
static int group_compare(const void*a, const void *b) {
|
||||
const Group *x = *(Group**)a, *y = *(Group**)b;
|
||||
|
||||
if (arg_order != ORDER_TASKS) {
|
||||
if (arg_order != ORDER_TASKS || arg_recursive) {
|
||||
/* Let's make sure that the parent is always before
|
||||
* the child. Except when ordering by tasks, since
|
||||
* that is actually not accumulative for all
|
||||
* children. */
|
||||
* the child. Except when ordering by tasks and
|
||||
* recursive summing is off, since that is actually
|
||||
* not accumulative for all children. */
|
||||
|
||||
if (path_startswith(y->path, x->path))
|
||||
return -1;
|
||||
|
@ -453,7 +494,7 @@ static int group_compare(const void*a, const void *b) {
|
|||
#define ON ANSI_HIGHLIGHT_ON
|
||||
#define OFF ANSI_HIGHLIGHT_OFF
|
||||
|
||||
static int display(Hashmap *a) {
|
||||
static void display(Hashmap *a) {
|
||||
Iterator i;
|
||||
Group *g;
|
||||
Group **array;
|
||||
|
@ -548,8 +589,6 @@ static int display(Hashmap *a) {
|
|||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void help(void) {
|
||||
|
@ -565,6 +604,8 @@ static void help(void) {
|
|||
" -r --raw Provide raw (not human-readable) numbers\n"
|
||||
" --cpu=percentage Show CPU usage as percentage (default)\n"
|
||||
" --cpu=time Show CPU usage as time\n"
|
||||
" -k Include kernel threads in task count\n"
|
||||
" --recursive=BOOL Sum up task count recursively\n"
|
||||
" -d --delay=DELAY Delay between updates\n"
|
||||
" -n --iterations=N Run for N iterations before exiting\n"
|
||||
" -b --batch Run in batch mode, accepting no input\n"
|
||||
|
@ -579,28 +620,29 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_DEPTH,
|
||||
ARG_CPU_TYPE,
|
||||
ARG_ORDER,
|
||||
ARG_RECURSIVE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "delay", required_argument, NULL, 'd' },
|
||||
{ "iterations", required_argument, NULL, 'n' },
|
||||
{ "batch", no_argument, NULL, 'b' },
|
||||
{ "raw", no_argument, NULL, 'r' },
|
||||
{ "depth", required_argument, NULL, ARG_DEPTH },
|
||||
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE },
|
||||
{ "order", required_argument, NULL, ARG_ORDER },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "delay", required_argument, NULL, 'd' },
|
||||
{ "iterations", required_argument, NULL, 'n' },
|
||||
{ "batch", no_argument, NULL, 'b' },
|
||||
{ "raw", no_argument, NULL, 'r' },
|
||||
{ "depth", required_argument, NULL, ARG_DEPTH },
|
||||
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE },
|
||||
{ "order", required_argument, NULL, ARG_ORDER },
|
||||
{ "recursive", required_argument, NULL, ARG_RECURSIVE },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
int r;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 1);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hptcmin:brd:", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "hptcmin:brd:k", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
|
@ -700,6 +742,20 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
arg_kernel_threads = true;
|
||||
break;
|
||||
|
||||
case ARG_RECURSIVE:
|
||||
r = parse_boolean(optarg);
|
||||
if (r < 0) {
|
||||
log_error("Failed to parse --recursive= argument: %s", optarg);
|
||||
return r;
|
||||
}
|
||||
|
||||
arg_recursive = r;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -721,6 +777,7 @@ int main(int argc, char *argv[]) {
|
|||
unsigned iteration = 0;
|
||||
usec_t last_refresh = 0;
|
||||
bool quit = false, immediate_refresh = false;
|
||||
_cleanup_free_ char *root = NULL;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
@ -729,6 +786,12 @@ int main(int argc, char *argv[]) {
|
|||
if (r <= 0)
|
||||
goto finish;
|
||||
|
||||
r = cg_get_root_path(&root);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to get root control group path: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
a = hashmap_new(&string_hash_ops);
|
||||
b = hashmap_new(&string_hash_ops);
|
||||
if (!a || !b) {
|
||||
|
@ -751,9 +814,11 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if (t >= last_refresh + arg_delay || immediate_refresh) {
|
||||
|
||||
r = refresh(a, b, iteration++);
|
||||
if (r < 0)
|
||||
r = refresh(root, a, b, iteration++);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to refresh: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
group_hashmap_clear(b);
|
||||
|
||||
|
@ -765,9 +830,7 @@ int main(int argc, char *argv[]) {
|
|||
immediate_refresh = false;
|
||||
}
|
||||
|
||||
r = display(b);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
display(b);
|
||||
|
||||
if (arg_iterations && iteration >= arg_iterations)
|
||||
break;
|
||||
|
@ -777,7 +840,7 @@ int main(int argc, char *argv[]) {
|
|||
fflush(stdout);
|
||||
|
||||
if (arg_batch)
|
||||
usleep(last_refresh + arg_delay - t);
|
||||
(void) usleep(last_refresh + arg_delay - t);
|
||||
else {
|
||||
r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL);
|
||||
if (r == -ETIMEDOUT)
|
||||
|
@ -830,6 +893,20 @@ int main(int argc, char *argv[]) {
|
|||
arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
arg_kernel_threads = !arg_kernel_threads;
|
||||
fprintf(stdout, "\nCounting kernel threads: %s.", yes_no(arg_kernel_threads));
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
arg_recursive = !arg_recursive;
|
||||
fprintf(stdout, "\nRecursive task counting: %s", yes_no(arg_recursive));
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (arg_delay < USEC_PER_SEC)
|
||||
arg_delay += USEC_PER_MSEC*250;
|
||||
|
@ -858,8 +935,8 @@ int main(int argc, char *argv[]) {
|
|||
case 'h':
|
||||
fprintf(stdout,
|
||||
"\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
|
||||
"\t<" ON "+" OFF "> Increase delay; <" ON "-" OFF "> Decrease delay; <" ON "%%" OFF "> Toggle time\n"
|
||||
"\t<" ON "q" OFF "> Quit; <" ON "SPACE" OFF "> Refresh");
|
||||
"\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n"
|
||||
"\t<" ON "k" OFF "> Count kernel threads; <" ON "r" OFF "> Count recursively; <" ON "q" OFF "> Quit");
|
||||
fflush(stdout);
|
||||
sleep(3);
|
||||
break;
|
||||
|
@ -881,10 +958,5 @@ finish:
|
|||
group_hashmap_free(a);
|
||||
group_hashmap_free(b);
|
||||
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Exiting with failure: %m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -806,12 +806,9 @@ static void unit_queue_siblings(Unit *u) {
|
|||
}
|
||||
|
||||
int unit_realize_cgroup(Unit *u) {
|
||||
CGroupContext *c;
|
||||
|
||||
assert(u);
|
||||
|
||||
c = unit_get_cgroup_context(u);
|
||||
if (!c)
|
||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
||||
return 0;
|
||||
|
||||
/* So, here's the deal: when realizing the cgroups for this
|
||||
|
|
|
@ -965,38 +965,39 @@ static int bus_unit_set_transient_property(
|
|||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
|
||||
} else if (streq(name, "Slice")) {
|
||||
Unit *slice;
|
||||
const char *s;
|
||||
|
||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
|
||||
if (u->type == UNIT_SLICE)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
|
||||
|
||||
r = sd_bus_message_read(message, "s", &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
|
||||
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
|
||||
|
||||
if (isempty(s)) {
|
||||
if (mode != UNIT_CHECK) {
|
||||
unit_ref_unset(&u->slice);
|
||||
unit_remove_drop_in(u, mode, name);
|
||||
}
|
||||
} else {
|
||||
Unit *slice;
|
||||
r = manager_load_unit(u->manager, s, NULL, error, &slice);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_load_unit(u->manager, s, NULL, error, &slice);
|
||||
if (slice->type != UNIT_SLICE)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
r = unit_set_slice(u, slice);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (slice->type != UNIT_SLICE)
|
||||
return -EINVAL;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
unit_ref_set(&u->slice, slice);
|
||||
unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
|
||||
}
|
||||
unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (STR_IN_SET(name,
|
||||
"Requires", "RequiresOverridable",
|
||||
"Requisite", "RequisiteOverridable",
|
||||
|
|
|
@ -381,7 +381,7 @@ static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *inter
|
|||
if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type)))
|
||||
return 0;
|
||||
|
||||
if (!unit_get_cgroup_context(u))
|
||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
||||
return 0;
|
||||
|
||||
*found = u;
|
||||
|
|
|
@ -2602,7 +2602,7 @@ int config_parse_unit_slice(
|
|||
void *userdata) {
|
||||
|
||||
_cleanup_free_ char *k = NULL;
|
||||
Unit *u = userdata, *slice;
|
||||
Unit *u = userdata, *slice = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -2611,29 +2611,23 @@ int config_parse_unit_slice(
|
|||
assert(u);
|
||||
|
||||
r = unit_name_printf(u, rvalue, &k);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, -r,
|
||||
"Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
|
||||
if (!k) {
|
||||
k = strdup(rvalue);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, -r,
|
||||
"Failed to load slice unit %s. Ignoring.", k);
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (slice->type != UNIT_SLICE) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Slice unit %s is not a slice. Ignoring.", k);
|
||||
r = unit_set_slice(u, slice);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unit_ref_set(&u->slice, slice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3603,6 +3597,11 @@ int unit_load_fragment(Unit *u) {
|
|||
assert(u->load_state == UNIT_STUB);
|
||||
assert(u->id);
|
||||
|
||||
if (u->transient) {
|
||||
u->load_state = UNIT_LOADED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First, try to find the unit under its id. We always look
|
||||
* for unit files in the default directories, to make it easy
|
||||
* to override things by placing things in /etc/systemd/system */
|
||||
|
|
|
@ -1391,8 +1391,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
/* clear the kernel timestamp,
|
||||
* because we are not PID 1 */
|
||||
kernel_timestamp.monotonic = 0ULL;
|
||||
kernel_timestamp.realtime = 0ULL;
|
||||
kernel_timestamp = DUAL_TIMESTAMP_NULL;
|
||||
}
|
||||
|
||||
/* Initialize default unit */
|
||||
|
|
|
@ -250,8 +250,8 @@ static int manager_dispatch_ask_password_fd(sd_event_source *source,
|
|||
static void manager_close_ask_password(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
|
||||
m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
|
||||
m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
|
||||
m->have_ask_password = -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -521,7 +521,7 @@ static int mount_add_extras(Mount *m) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_add_default_slice(u, &m->cgroup_context);
|
||||
r = unit_set_default_slice(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ static int scope_load(Unit *u) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_add_default_slice(u, &s->cgroup_context);
|
||||
r = unit_set_default_slice(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -556,7 +556,7 @@ static int service_add_extras(Service *s) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_add_default_slice(UNIT(s), &s->cgroup_context);
|
||||
r = unit_set_default_slice(UNIT(s));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -345,7 +345,7 @@ static int socket_add_extras(Socket *s) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_add_default_slice(u, &s->cgroup_context);
|
||||
r = unit_set_default_slice(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -326,7 +326,7 @@ static int swap_load(Unit *u) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_add_default_slice(u, &s->cgroup_context);
|
||||
r = unit_set_default_slice(u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -405,17 +405,17 @@ static void unit_remove_transient(Unit *u) {
|
|||
return;
|
||||
|
||||
if (u->fragment_path)
|
||||
unlink(u->fragment_path);
|
||||
(void) unlink(u->fragment_path);
|
||||
|
||||
STRV_FOREACH(i, u->dropin_paths) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
unlink(*i);
|
||||
(void) unlink(*i);
|
||||
|
||||
r = path_get_parent(*i, &p);
|
||||
if (r >= 0)
|
||||
rmdir(p);
|
||||
(void) rmdir(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1122,7 +1122,7 @@ static int unit_add_target_dependencies(Unit *u) {
|
|||
static int unit_add_slice_dependencies(Unit *u) {
|
||||
assert(u);
|
||||
|
||||
if (!unit_get_cgroup_context(u))
|
||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
||||
return 0;
|
||||
|
||||
if (UNIT_ISSET(u->slice))
|
||||
|
@ -2424,14 +2424,42 @@ char *unit_default_cgroup_path(Unit *u) {
|
|||
return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
|
||||
}
|
||||
|
||||
int unit_add_default_slice(Unit *u, CGroupContext *c) {
|
||||
int unit_set_slice(Unit *u, Unit *slice) {
|
||||
assert(u);
|
||||
assert(slice);
|
||||
|
||||
/* Sets the unit slice if it has not been set before. Is extra
|
||||
* careful, to only allow this for units that actually have a
|
||||
* cgroup context. Also, we don't allow to set this for slices
|
||||
* (since the parent slice is derived from the name). Make
|
||||
* sure the unit we set is actually a slice. */
|
||||
|
||||
if (!UNIT_HAS_CGROUP_CONTEXT(u))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (u->type == UNIT_SLICE)
|
||||
return -EINVAL;
|
||||
|
||||
if (slice->type != UNIT_SLICE)
|
||||
return -EINVAL;
|
||||
|
||||
if (UNIT_DEREF(u->slice) == slice)
|
||||
return 0;
|
||||
|
||||
if (UNIT_ISSET(u->slice))
|
||||
return -EBUSY;
|
||||
|
||||
unit_ref_set(&u->slice, slice);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unit_set_default_slice(Unit *u) {
|
||||
_cleanup_free_ char *b = NULL;
|
||||
const char *slice_name;
|
||||
Unit *slice;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(c);
|
||||
|
||||
if (UNIT_ISSET(u->slice))
|
||||
return 0;
|
||||
|
@ -2471,8 +2499,7 @@ int unit_add_default_slice(Unit *u, CGroupContext *c) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unit_ref_set(&u->slice, slice);
|
||||
return 0;
|
||||
return unit_set_slice(u, slice);
|
||||
}
|
||||
|
||||
const char *unit_slice_name(Unit *u) {
|
||||
|
@ -3108,17 +3135,17 @@ int unit_kill_common(
|
|||
|
||||
int r = 0;
|
||||
|
||||
if (who == KILL_MAIN && main_pid <= 0) {
|
||||
if (who == KILL_MAIN) {
|
||||
if (main_pid < 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
|
||||
else
|
||||
else if (main_pid == 0)
|
||||
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
|
||||
}
|
||||
|
||||
if (who == KILL_CONTROL && control_pid <= 0) {
|
||||
if (who == KILL_CONTROL) {
|
||||
if (control_pid < 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
|
||||
else
|
||||
else if (control_pid == 0)
|
||||
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
|
||||
}
|
||||
|
||||
|
@ -3317,6 +3344,8 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
|
|||
}
|
||||
|
||||
static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) {
|
||||
assert(u);
|
||||
|
||||
if (u->manager->running_as == MANAGER_USER) {
|
||||
int r;
|
||||
|
||||
|
@ -3324,9 +3353,9 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient,
|
|||
r = user_config_home(dir);
|
||||
else
|
||||
r = user_runtime_dir(dir);
|
||||
|
||||
if (r == 0)
|
||||
return -ENOENT;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -3340,8 +3369,7 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int unit_drop_in_file(Unit *u,
|
||||
UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
|
||||
static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
|
||||
_cleanup_free_ char *dir = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -3475,40 +3503,17 @@ int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
|
|||
}
|
||||
|
||||
int unit_make_transient(Unit *u) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
if (!UNIT_VTABLE(u)->can_transient)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
u->load_state = UNIT_STUB;
|
||||
u->load_error = 0;
|
||||
u->transient = true;
|
||||
u->fragment_path = mfree(u->fragment_path);
|
||||
|
||||
free(u->fragment_path);
|
||||
u->fragment_path = NULL;
|
||||
|
||||
if (u->manager->running_as == MANAGER_USER) {
|
||||
_cleanup_free_ char *c = NULL;
|
||||
|
||||
r = user_runtime_dir(&c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -ENOENT;
|
||||
|
||||
u->fragment_path = strjoin(c, "/", u->id, NULL);
|
||||
if (!u->fragment_path)
|
||||
return -ENOMEM;
|
||||
|
||||
mkdir_p(c, 0755);
|
||||
} else {
|
||||
u->fragment_path = strappend("/run/systemd/system/", u->id);
|
||||
if (!u->fragment_path)
|
||||
return -ENOMEM;
|
||||
|
||||
mkdir_p("/run/systemd/system", 0755);
|
||||
}
|
||||
|
||||
return write_string_file_atomic_label(u->fragment_path, "# Transient stub");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_kill_context(
|
||||
|
|
|
@ -439,6 +439,10 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
|
|||
/* For casting the various unit types into a unit */
|
||||
#define UNIT(u) (&(u)->meta)
|
||||
|
||||
#define UNIT_HAS_EXEC_CONTEXT(u) (UNIT_VTABLE(u)->exec_context_offset > 0)
|
||||
#define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0)
|
||||
#define UNIT_HAS_KILL_CONTEXT(u) (UNIT_VTABLE(u)->kill_context_offset > 0)
|
||||
|
||||
#define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS]))
|
||||
|
||||
DEFINE_CAST(SERVICE, Service);
|
||||
|
@ -490,7 +494,8 @@ int unit_load_fragment_and_dropin(Unit *u);
|
|||
int unit_load_fragment_and_dropin_optional(Unit *u);
|
||||
int unit_load(Unit *unit);
|
||||
|
||||
int unit_add_default_slice(Unit *u, CGroupContext *c);
|
||||
int unit_set_slice(Unit *u, Unit *slice);
|
||||
int unit_set_default_slice(Unit *u);
|
||||
|
||||
const char *unit_description(Unit *u) _pure_;
|
||||
|
||||
|
|
|
@ -481,7 +481,8 @@ static void source_io_unregister(sd_event_source *s) {
|
|||
return;
|
||||
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
|
||||
assert_log(r >= 0);
|
||||
if (r < 0)
|
||||
log_debug_errno(errno, "Failed to remove source %s from epoll: %m", strna(s->description));
|
||||
|
||||
s->io.registered = false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../Makefile
|
|
@ -82,7 +82,7 @@ int pager_open(bool jump_to_end) {
|
|||
|
||||
/* In the child start the pager */
|
||||
if (pager_pid == 0) {
|
||||
const char* less_opts;
|
||||
const char* less_opts, *less_charset;
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
@ -90,6 +90,7 @@ int pager_open(bool jump_to_end) {
|
|||
dup2(fd[0], STDIN_FILENO);
|
||||
safe_close_pair(fd);
|
||||
|
||||
/* Initialize a good set of less options */
|
||||
less_opts = getenv("SYSTEMD_LESS");
|
||||
if (!less_opts)
|
||||
less_opts = "FRSXMK";
|
||||
|
@ -97,6 +98,15 @@ int pager_open(bool jump_to_end) {
|
|||
less_opts = strjoina(less_opts, " +G");
|
||||
setenv("LESS", less_opts, 1);
|
||||
|
||||
/* Initialize a good charset for less. This is
|
||||
* particularly important if we output UTF-8
|
||||
* characters. */
|
||||
less_charset = getenv("SYSTEMD_LESSCHARSET");
|
||||
if (!less_charset && is_locale_utf8())
|
||||
less_charset = "utf-8";
|
||||
if (less_charset)
|
||||
setenv("LESSCHARSET", less_charset, 1);
|
||||
|
||||
/* Make sure the pager goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
|
Loading…
Reference in New Issue