Merge pull request #1093 from poettering/unified-prepare

A variety of clean-ups
This commit is contained in:
Daniel Mack 2015-08-31 13:58:29 +02:00
commit d728d7faa6
21 changed files with 301 additions and 164 deletions

View File

@ -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>

View File

@ -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");

View File

@ -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");

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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",

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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(

View File

@ -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_;

View File

@ -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;
}

1
src/shared/Makefile Symbolic link
View File

@ -0,0 +1 @@
../Makefile

View File

@ -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);