2017-11-18 17:09:20 +01:00
/* SPDX-License-Identifier: LGPL-2.1+ */
2010-02-03 13:03:47 +01:00
2013-11-19 21:12:59 +01:00
# include "sd-bus.h"
2015-10-24 22:58:24 +02:00
2015-10-27 03:01:06 +01:00
# include "alloc-util.h"
2017-09-05 19:27:53 +02:00
# include "bpf-firewall.h"
2015-10-24 22:58:24 +02:00
# include "bus-common-errors.h"
# include "cgroup-util.h"
2018-01-01 16:26:34 +01:00
# include "condition.h"
2016-11-15 19:32:50 +01:00
# include "dbus-job.h"
2015-10-26 23:01:30 +01:00
# include "dbus-unit.h"
2018-01-01 16:26:34 +01:00
# include "dbus-util.h"
2015-10-24 22:58:24 +02:00
# include "dbus.h"
2016-04-20 15:28:28 +02:00
# include "fd-util.h"
2015-10-26 23:01:30 +01:00
# include "locale-util.h"
2010-02-01 03:33:24 +01:00
# include "log.h"
2018-01-01 16:26:34 +01:00
# include "path-util.h"
2016-04-20 15:28:28 +02:00
# include "process-util.h"
2012-09-06 22:23:11 +02:00
# include "selinux-access.h"
2016-04-08 11:27:28 +02:00
# include "signal-util.h"
core: unified cgroup hierarchy support
This patch set adds full support the new unified cgroup hierarchy logic
of modern kernels.
A new kernel command line option "systemd.unified_cgroup_hierarchy=1" is
added. If specified the unified hierarchy is mounted to /sys/fs/cgroup
instead of a tmpfs. No further hierarchies are mounted. The kernel
command line option defaults to off. We can turn it on by default as
soon as the kernel's APIs regarding this are stabilized (but even then
downstream distros might want to turn this off, as this will break any
tools that access cgroupfs directly).
It is possibly to choose for each boot individually whether the unified
or the legacy hierarchy is used. nspawn will by default provide the
legacy hierarchy to containers if the host is using it, and the unified
otherwise. However it is possible to run containers with the unified
hierarchy on a legacy host and vice versa, by setting the
$UNIFIED_CGROUP_HIERARCHY environment variable for nspawn to 1 or 0,
respectively.
The unified hierarchy provides reliable cgroup empty notifications for
the first time, via inotify. To make use of this we maintain one
manager-wide inotify fd, and each cgroup to it.
This patch also removes cg_delete() which is unused now.
On kernel 4.2 only the "memory" controller is compatible with the
unified hierarchy, hence that's the only controller systemd exposes when
booted in unified heirarchy mode.
This introduces a new enum for enumerating supported controllers, plus a
related enum for the mask bits mapping to it. The core is changed to
make use of this everywhere.
This moves PID 1 into a new "init.scope" implicit scope unit in the root
slice. This is necessary since on the unified hierarchy cgroups may
either contain subgroups or processes but not both. PID 1 hence has to
move out of the root cgroup (strictly speaking the root cgroup is the
only one where processes and subgroups are still allowed, but in order
to support containers nicey, we move PID 1 into the new scope in all
cases.) This new unit is also used on legacy hierarchy setups. It's
actually pretty useful on all systems, as it can then be used to filter
journal messages coming from PID 1, and so on.
The root slice ("-.slice") is now implicitly created and started (and
does not require a unit file on disk anymore), since
that's where "init.scope" is located and the slice needs to be started
before the scope can.
To check whether we are in unified or legacy hierarchy mode we use
statfs() on /sys/fs/cgroup. If the .f_type field reports tmpfs we are in
legacy mode, if it reports cgroupfs we are in unified mode.
This patch set carefuly makes sure that cgls and cgtop continue to work
as desired.
When invoking nspawn as a service it will implicitly create two
subcgroups in the cgroup it is using, one to move the nspawn process
into, the other to move the actual container processes into. This is
done because of the requirement that cgroups may either contain
processes or other subgroups.
2015-09-01 19:22:36 +02:00
# include "special.h"
2019-03-22 11:47:29 +01:00
# include "string-table.h"
2015-10-24 22:58:24 +02:00
# include "string-util.h"
# include "strv.h"
2015-10-27 00:42:07 +01:00
# include "user-util.h"
2018-01-01 16:26:34 +01:00
# include "web-util.h"
2013-11-19 21:12:59 +01:00
2018-05-14 05:37:57 +02:00
static bool unit_can_start_refuse_manual ( Unit * u ) {
return unit_can_start ( u ) & & ! u - > refuse_manual_start ;
}
static bool unit_can_stop_refuse_manual ( Unit * u ) {
return unit_can_stop ( u ) & & ! u - > refuse_manual_stop ;
}
static bool unit_can_isolate_refuse_manual ( Unit * u ) {
return unit_can_isolate ( u ) & & ! u - > refuse_manual_start ;
}
2017-11-13 17:14:07 +01:00
static BUS_DEFINE_PROPERTY_GET_ENUM ( property_get_collect_mode , collect_mode , CollectMode ) ;
2013-11-19 21:12:59 +01:00
static BUS_DEFINE_PROPERTY_GET_ENUM ( property_get_load_state , unit_load_state , UnitLoadState ) ;
2013-11-26 01:39:53 +01:00
static BUS_DEFINE_PROPERTY_GET_ENUM ( property_get_job_mode , job_mode , JobMode ) ;
2016-10-20 15:27:37 +02:00
static BUS_DEFINE_PROPERTY_GET_ENUM ( property_get_emergency_action , emergency_action , EmergencyAction ) ;
2018-05-11 11:11:18 +02:00
static BUS_DEFINE_PROPERTY_GET ( property_get_description , " s " , Unit , unit_description ) ;
static BUS_DEFINE_PROPERTY_GET2 ( property_get_active_state , " s " , Unit , unit_active_state , unit_active_state_to_string ) ;
static BUS_DEFINE_PROPERTY_GET ( property_get_sub_state , " s " , Unit , unit_sub_state_to_string ) ;
static BUS_DEFINE_PROPERTY_GET2 ( property_get_unit_file_state , " s " , Unit , unit_get_unit_file_state , unit_file_state_to_string ) ;
static BUS_DEFINE_PROPERTY_GET ( property_get_can_reload , " b " , Unit , unit_can_reload ) ;
2018-05-14 05:37:57 +02:00
static BUS_DEFINE_PROPERTY_GET ( property_get_can_start , " b " , Unit , unit_can_start_refuse_manual ) ;
static BUS_DEFINE_PROPERTY_GET ( property_get_can_stop , " b " , Unit , unit_can_stop_refuse_manual ) ;
static BUS_DEFINE_PROPERTY_GET ( property_get_can_isolate , " b " , Unit , unit_can_isolate_refuse_manual ) ;
2018-05-11 11:11:18 +02:00
static BUS_DEFINE_PROPERTY_GET ( property_get_need_daemon_reload , " b " , Unit , unit_need_daemon_reload ) ;
2018-05-14 03:07:00 +02:00
static BUS_DEFINE_PROPERTY_GET_GLOBAL ( property_get_empty_strv , " as " , 0 ) ;
2013-11-19 21:12:59 +01:00
static int property_get_names (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
2013-11-19 21:12:59 +01:00
2018-05-14 05:38:57 +02:00
Set * * s = userdata ;
2013-11-19 21:12:59 +01:00
Iterator i ;
const char * t ;
int r ;
2010-02-01 03:33:24 +01:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
2018-05-14 05:38:57 +02:00
assert ( s ) ;
2010-04-18 03:08:16 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_open_container ( reply , ' a ' , " s " ) ;
if ( r < 0 )
return r ;
2010-04-18 03:08:16 +02:00
2018-05-14 05:38:57 +02:00
SET_FOREACH ( t , * s , i ) {
2013-11-19 21:12:59 +01:00
r = sd_bus_message_append ( reply , " s " , t ) ;
if ( r < 0 )
return r ;
}
2010-04-18 03:08:16 +02:00
2013-11-19 21:12:59 +01:00
return sd_bus_message_close_container ( reply ) ;
2010-04-18 03:08:16 +02:00
}
2013-11-19 21:12:59 +01:00
static int property_get_following (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
2013-11-19 21:12:59 +01:00
Unit * u = userdata , * f ;
2010-07-20 20:33:19 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
2010-07-20 20:33:19 +02:00
assert ( u ) ;
2010-07-21 05:00:29 +02:00
f = unit_following ( u ) ;
2018-05-10 18:22:49 +02:00
return sd_bus_message_append ( reply , " s " , f ? f - > id : NULL ) ;
2010-07-20 20:33:19 +02:00
}
2013-11-19 21:12:59 +01:00
static int property_get_dependencies (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
2013-06-18 01:00:13 +02:00
2018-05-11 11:12:12 +02:00
Hashmap * * h = userdata ;
2010-05-16 16:20:24 +02:00
Iterator j ;
2013-11-19 21:12:59 +01:00
Unit * u ;
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
void * v ;
2013-11-19 21:12:59 +01:00
int r ;
2010-05-16 16:20:24 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
2018-05-11 11:12:12 +02:00
assert ( h ) ;
2010-05-16 16:20:24 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_open_container ( reply , ' a ' , " s " ) ;
if ( r < 0 )
return r ;
2010-05-16 16:20:24 +02:00
2018-05-11 11:12:12 +02:00
HASHMAP_FOREACH_KEY ( v , u , * h , j ) {
2013-11-19 21:12:59 +01:00
r = sd_bus_message_append ( reply , " s " , u - > id ) ;
if ( r < 0 )
return r ;
}
2010-05-16 16:20:24 +02:00
2013-11-19 21:12:59 +01:00
return sd_bus_message_close_container ( reply ) ;
2010-05-16 16:20:24 +02:00
}
2017-11-14 09:01:21 +01:00
static int property_get_requires_mounts_for (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
2018-05-11 11:12:12 +02:00
Hashmap * * h = userdata ;
2017-11-14 09:01:21 +01:00
const char * p ;
2017-11-14 21:50:59 +01:00
Iterator j ;
2017-11-14 09:01:21 +01:00
void * v ;
int r ;
assert ( bus ) ;
assert ( reply ) ;
2018-05-11 11:12:12 +02:00
assert ( h ) ;
2017-11-14 09:01:21 +01:00
r = sd_bus_message_open_container ( reply , ' a ' , " s " ) ;
if ( r < 0 )
return r ;
2018-05-11 11:12:12 +02:00
HASHMAP_FOREACH_KEY ( v , p , * h , j ) {
2017-11-14 09:01:21 +01:00
r = sd_bus_message_append ( reply , " s " , p ) ;
if ( r < 0 )
return r ;
}
return sd_bus_message_close_container ( reply ) ;
}
2014-12-02 02:38:18 +01:00
static int property_get_unit_file_preset (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
Unit * u = userdata ;
int r ;
assert ( bus ) ;
assert ( reply ) ;
assert ( u ) ;
r = unit_get_unit_file_preset ( u ) ;
return sd_bus_message_append ( reply , " s " ,
2018-05-10 18:22:49 +02:00
r < 0 ? NULL :
2014-12-02 02:38:18 +01:00
r > 0 ? " enabled " : " disabled " ) ;
}
2013-11-19 21:12:59 +01:00
static int property_get_job (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
2013-11-19 21:12:59 +01:00
2013-01-02 22:19:07 +01:00
_cleanup_free_ char * p = NULL ;
2018-05-14 05:38:57 +02:00
Job * * j = userdata ;
2010-02-02 12:22:59 +01:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
2018-05-14 05:38:57 +02:00
assert ( j ) ;
2010-02-02 12:22:59 +01:00
2018-05-14 05:38:57 +02:00
if ( ! * j )
2013-11-19 21:12:59 +01:00
return sd_bus_message_append ( reply , " (uo) " , 0, " / " ) ;
2010-02-02 12:22:59 +01:00
2018-05-14 05:38:57 +02:00
p = job_dbus_path ( * j ) ;
2013-11-19 21:12:59 +01:00
if ( ! p )
return - ENOMEM ;
2010-02-02 12:22:59 +01:00
2018-05-14 05:38:57 +02:00
return sd_bus_message_append ( reply , " (uo) " , (*j)->id, p) ;
2013-11-19 21:12:59 +01:00
}
2010-02-02 12:22:59 +01:00
2013-11-19 21:12:59 +01:00
static int property_get_conditions (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
2010-07-17 00:57:51 +02:00
2014-11-06 13:43:45 +01:00
const char * ( * to_string ) ( ConditionType type ) = NULL ;
Condition * * list = userdata , * c ;
2013-11-19 21:12:59 +01:00
int r ;
2010-07-17 00:57:51 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
2014-11-06 13:43:45 +01:00
assert ( list ) ;
to_string = streq ( property , " Asserts " ) ? assert_type_to_string : condition_type_to_string ;
2010-07-17 00:57:51 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_open_container ( reply , ' a ' , " (sbbsi) " ) ;
if ( r < 0 )
return r ;
2010-07-17 00:57:51 +02:00
2014-11-06 13:43:45 +01:00
LIST_FOREACH ( conditions , c , * list ) {
2014-11-06 02:27:10 +01:00
int tristate ;
tristate =
c - > result = = CONDITION_UNTESTED ? 0 :
c - > result = = CONDITION_SUCCEEDED ? 1 : - 1 ;
2013-11-25 17:18:38 +01:00
r = sd_bus_message_append ( reply , " (sbbsi) " ,
2014-11-06 13:43:45 +01:00
to_string ( c - > type ) ,
2013-11-25 17:18:38 +01:00
c - > trigger , c - > negate ,
2014-11-06 02:27:10 +01:00
c - > parameter , tristate ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
return r ;
2010-07-17 00:57:51 +02:00
2013-11-19 21:12:59 +01:00
}
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
2013-11-19 21:12:59 +01:00
return sd_bus_message_close_container ( reply ) ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
}
2013-11-19 21:12:59 +01:00
static int property_get_load_error (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_error_free ) sd_bus_error e = SD_BUS_ERROR_NULL ;
2018-06-01 17:32:54 +02:00
Unit * u = userdata ;
int r ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
2018-06-01 17:32:54 +02:00
assert ( u ) ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
2018-06-01 17:32:54 +02:00
r = bus_unit_validate_load_state ( u , & e ) ;
if ( r < 0 )
return sd_bus_message_append ( reply , " (ss) " , e.name, e.message) ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
2018-06-01 17:32:54 +02:00
return sd_bus_message_append ( reply , " (ss) " , NULL, NULL) ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
}
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
static int bus_verify_manage_units_async_full (
Unit * u ,
const char * verb ,
int capability ,
const char * polkit_message ,
2016-08-15 18:12:01 +02:00
bool interactive ,
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
sd_bus_message * call ,
sd_bus_error * error ) {
const char * details [ 9 ] = {
" unit " , u - > id ,
" verb " , verb ,
} ;
if ( polkit_message ) {
details [ 4 ] = " polkit.message " ;
details [ 5 ] = polkit_message ;
details [ 6 ] = " polkit.gettext_domain " ;
details [ 7 ] = GETTEXT_PACKAGE ;
}
2016-08-15 18:12:01 +02:00
return bus_verify_polkit_async (
call ,
capability ,
" org.freedesktop.systemd1.manage-units " ,
details ,
interactive ,
UID_INVALID ,
& u - > manager - > polkit_registry ,
error ) ;
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
}
2019-03-22 20:57:30 +01:00
static const char * const polkit_message_for_job [ _JOB_TYPE_MAX ] = {
[ JOB_START ] = N_ ( " Authentication is required to start '$(unit)'. " ) ,
[ JOB_STOP ] = N_ ( " Authentication is required to stop '$(unit)'. " ) ,
[ JOB_RELOAD ] = N_ ( " Authentication is required to reload '$(unit)'. " ) ,
[ JOB_RESTART ] = N_ ( " Authentication is required to restart '$(unit)'. " ) ,
[ JOB_TRY_RESTART ] = N_ ( " Authentication is required to restart '$(unit)'. " ) ,
} ;
2015-02-18 17:40:57 +01:00
int bus_unit_method_start_generic (
sd_bus_message * message ,
Unit * u ,
JobType job_type ,
bool reload_if_possible ,
sd_bus_error * error ) {
2019-03-22 19:21:48 +01:00
const char * smode , * verb ;
2013-11-19 21:12:59 +01:00
JobMode mode ;
int r ;
2011-07-31 18:13:03 +02:00
2013-11-19 21:12:59 +01:00
assert ( message ) ;
2011-07-31 18:13:03 +02:00
assert ( u ) ;
2013-11-19 21:12:59 +01:00
assert ( job_type > = 0 & & job_type < _JOB_TYPE_MAX ) ;
2011-07-31 18:13:03 +02:00
2016-01-31 13:59:35 +01:00
r = mac_selinux_unit_access_check (
u , message ,
2016-01-31 14:26:09 +01:00
job_type_to_access_method ( job_type ) ,
error ) ;
2015-02-18 17:40:57 +01:00
if ( r < 0 )
return r ;
2013-11-19 21:12:59 +01:00
r = sd_bus_message_read ( message , " s " , & smode ) ;
if ( r < 0 )
2013-11-21 19:34:37 +01:00
return r ;
2011-07-31 18:13:03 +02:00
2013-11-19 21:12:59 +01:00
mode = job_mode_from_string ( smode ) ;
if ( mode < 0 )
2013-11-21 19:34:37 +01:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Job mode %s invalid " , smode ) ;
2011-07-31 18:13:03 +02:00
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
if ( reload_if_possible )
2019-03-22 19:21:48 +01:00
verb = strjoina ( " reload-or- " , job_type_to_string ( job_type ) ) ;
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
else
2019-03-22 19:21:48 +01:00
verb = job_type_to_string ( job_type ) ;
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
r = bus_verify_manage_units_async_full (
u ,
verb ,
CAP_SYS_ADMIN ,
2019-03-22 19:22:53 +01:00
polkit_message_for_job [ job_type ] ,
2016-08-15 18:12:01 +02:00
true ,
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
message ,
error ) ;
2015-02-18 17:40:57 +01:00
if ( r < 0 )
return r ;
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2019-03-22 20:57:30 +01:00
return bus_unit_queue_job ( message , u , job_type , mode ,
reload_if_possible ? BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE : 0 , error ) ;
2011-07-31 18:13:03 +02:00
}
2015-04-29 18:35:10 +02:00
static int method_start ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_START , false , error ) ;
2013-11-19 21:12:59 +01:00
}
2010-02-03 12:37:42 +01:00
2015-04-29 18:35:10 +02:00
static int method_stop ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_STOP , false , error ) ;
2013-11-19 21:12:59 +01:00
}
2015-04-29 18:35:10 +02:00
static int method_reload ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_RELOAD , false , error ) ;
2013-11-19 21:12:59 +01:00
}
2011-07-13 19:56:40 +02:00
2015-04-29 18:35:10 +02:00
static int method_restart ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_RESTART , false , error ) ;
2013-11-19 21:12:59 +01:00
}
2010-10-22 16:11:50 +02:00
2015-04-29 18:35:10 +02:00
static int method_try_restart ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_TRY_RESTART , false , error ) ;
2013-11-19 21:12:59 +01:00
}
2012-10-02 23:07:00 +02:00
2015-04-29 18:35:10 +02:00
static int method_reload_or_restart ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_RESTART , true , error ) ;
2013-11-19 21:12:59 +01:00
}
2010-10-22 16:11:50 +02:00
2015-04-29 18:35:10 +02:00
static int method_reload_or_try_restart ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return bus_unit_method_start_generic ( message , userdata , JOB_TRY_RESTART , true , error ) ;
2013-11-19 21:12:59 +01:00
}
2010-10-22 16:11:50 +02:00
2019-03-22 20:57:30 +01:00
int bus_unit_method_enqueue_job ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
BusUnitQueueFlags flags = BUS_UNIT_QUEUE_VERBOSE_REPLY ;
const char * jtype , * smode ;
Unit * u = userdata ;
JobType type ;
JobMode mode ;
int r ;
assert ( message ) ;
assert ( u ) ;
r = sd_bus_message_read ( message , " ss " , & jtype , & smode ) ;
if ( r < 0 )
return r ;
/* Parse the two magic reload types "reload-or-…" manually */
if ( streq ( jtype , " reload-or-restart " ) ) {
type = JOB_RESTART ;
flags | = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE ;
} else if ( streq ( jtype , " reload-or-try-restart " ) ) {
type = JOB_TRY_RESTART ;
flags | = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE ;
} else {
/* And the rest generically */
type = job_type_from_string ( jtype ) ;
if ( type < 0 )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Job type %s invalid " , jtype ) ;
}
mode = job_mode_from_string ( smode ) ;
if ( mode < 0 )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Job mode %s invalid " , smode ) ;
r = mac_selinux_unit_access_check (
u , message ,
job_type_to_access_method ( type ) ,
error ) ;
if ( r < 0 )
return r ;
r = bus_verify_manage_units_async_full (
u ,
jtype ,
CAP_SYS_ADMIN ,
polkit_message_for_job [ type ] ,
true ,
message ,
error ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
return bus_unit_queue_job ( message , u , type , mode , flags , error ) ;
}
2015-04-29 18:35:10 +02:00
int bus_unit_method_kill ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-19 21:12:59 +01:00
Unit * u = userdata ;
const char * swho ;
int32_t signo ;
KillWho who ;
int r ;
2010-07-18 04:58:01 +02:00
2013-11-19 21:12:59 +01:00
assert ( message ) ;
assert ( u ) ;
2012-10-02 23:07:00 +02:00
2015-02-18 17:40:57 +01:00
r = mac_selinux_unit_access_check ( u , message , " stop " , error ) ;
2014-08-06 11:45:36 +02:00
if ( r < 0 )
return r ;
2013-11-19 21:12:59 +01:00
r = sd_bus_message_read ( message , " si " , & swho , & signo ) ;
if ( r < 0 )
2013-11-21 19:34:37 +01:00
return r ;
2013-11-19 21:12:59 +01:00
if ( isempty ( swho ) )
who = KILL_ALL ;
else {
who = kill_who_from_string ( swho ) ;
if ( who < 0 )
2013-11-21 19:34:37 +01:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Invalid who argument %s " , swho ) ;
2013-11-19 21:12:59 +01:00
}
2010-07-18 04:58:01 +02:00
2016-04-08 11:27:28 +02:00
if ( ! SIGNAL_VALID ( signo ) )
2013-11-21 19:34:37 +01:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Signal number out of range. " ) ;
2013-06-27 21:14:56 +02:00
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
r = bus_verify_manage_units_async_full (
u ,
" kill " ,
CAP_KILL ,
2018-10-25 23:01:41 +02:00
N_ ( " Authentication is required to send a UNIX signal to the processes of '$(unit)'. " ) ,
2016-08-15 18:12:01 +02:00
true ,
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
message ,
error ) ;
2013-11-21 19:34:37 +01:00
if ( r < 0 )
return r ;
2015-02-18 17:40:57 +01:00
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2013-06-27 21:14:56 +02:00
2013-11-21 19:34:37 +01:00
r = unit_kill ( u , who , signo , error ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
2013-11-21 19:34:37 +01:00
return r ;
2013-06-27 21:14:56 +02:00
2013-11-21 01:51:16 +01:00
return sd_bus_reply_method_return ( message , NULL ) ;
2013-11-19 21:12:59 +01:00
}
2013-06-27 21:14:56 +02:00
2015-04-29 18:35:10 +02:00
int bus_unit_method_reset_failed ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-19 21:12:59 +01:00
Unit * u = userdata ;
2013-11-21 19:34:37 +01:00
int r ;
2010-02-03 12:37:42 +01:00
2013-11-19 21:12:59 +01:00
assert ( message ) ;
assert ( u ) ;
2010-02-03 12:37:42 +01:00
2015-02-18 17:40:57 +01:00
r = mac_selinux_unit_access_check ( u , message , " reload " , error ) ;
2014-08-06 11:45:36 +02:00
if ( r < 0 )
return r ;
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
r = bus_verify_manage_units_async_full (
u ,
" reset-failed " ,
CAP_SYS_ADMIN ,
N_ ( " Authentication is required to reset the \" failed \" state of '$(unit)'. " ) ,
2016-08-15 18:12:01 +02:00
true ,
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
message ,
error ) ;
2013-11-21 19:34:37 +01:00
if ( r < 0 )
return r ;
2015-02-18 17:40:57 +01:00
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2010-02-03 12:37:42 +01:00
2013-11-19 21:12:59 +01:00
unit_reset_failed ( u ) ;
2010-02-03 12:37:42 +01:00
2013-11-21 01:51:16 +01:00
return sd_bus_reply_method_return ( message , NULL ) ;
2010-02-01 03:33:24 +01:00
}
2015-04-29 18:35:10 +02:00
int bus_unit_method_set_properties ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-19 21:12:59 +01:00
Unit * u = userdata ;
int runtime , r ;
2010-02-01 03:33:24 +01:00
assert ( message ) ;
2013-11-19 21:12:59 +01:00
assert ( u ) ;
2012-05-21 12:54:34 +02:00
2015-02-18 17:40:57 +01:00
r = mac_selinux_unit_access_check ( u , message , " start " , error ) ;
2014-08-06 11:45:36 +02:00
if ( r < 0 )
return r ;
2013-11-19 21:12:59 +01:00
r = sd_bus_message_read ( message , " b " , & runtime ) ;
if ( r < 0 )
2013-11-21 19:34:37 +01:00
return r ;
2010-10-13 03:03:31 +02:00
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
r = bus_verify_manage_units_async_full (
u ,
" set-property " ,
CAP_SYS_ADMIN ,
N_ ( " Authentication is required to set properties on '$(unit)'. " ) ,
2016-08-15 18:12:01 +02:00
true ,
core: pass details to polkit for some unit actions
The following details are passed:
- unit: the primary name of the unit upon which the action was
invoked (i.e. after resolving any aliases);
- verb: one of 'start', 'stop', 'reload', 'restart', 'try-restart',
'reload-or-restart', 'reload-or-try-restart', 'kill',
'reset-failed', or 'set-property', corresponding to the
systemctl verb used to invoke the action.
Typical use of these details in a polkit policy rule might be:
// Allow alice to manage example.service;
// fall back to implicit authorization otherwise.
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "example.service" &&
subject.user == "alice") {
return polkit.Result.YES;
}
});
We also supply a custom polkit message that includes the unit's name and
the requested operation.
2015-09-05 16:07:17 +02:00
message ,
error ) ;
2013-11-21 19:34:37 +01:00
if ( r < 0 )
return r ;
2015-02-18 17:40:57 +01:00
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2012-10-02 23:07:00 +02:00
2013-11-21 19:34:37 +01:00
r = bus_unit_set_properties ( u , message , runtime ? UNIT_RUNTIME : UNIT_PERSISTENT , true , error ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
2013-11-21 19:34:37 +01:00
return r ;
2010-10-13 03:03:31 +02:00
2013-11-21 01:51:16 +01:00
return sd_bus_reply_method_return ( message , NULL ) ;
2013-11-19 21:12:59 +01:00
}
2010-10-13 03:03:31 +02:00
2016-08-15 18:12:01 +02:00
int bus_unit_method_ref ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
Unit * u = userdata ;
int r ;
assert ( message ) ;
assert ( u ) ;
r = mac_selinux_unit_access_check ( u , message , " start " , error ) ;
if ( r < 0 )
return r ;
r = bus_verify_manage_units_async_full (
u ,
" ref " ,
CAP_SYS_ADMIN ,
NULL ,
false ,
message ,
error ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = bus_unit_track_add_sender ( u , message ) ;
if ( r < 0 )
return r ;
return sd_bus_reply_method_return ( message , NULL ) ;
}
int bus_unit_method_unref ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
Unit * u = userdata ;
int r ;
assert ( message ) ;
assert ( u ) ;
r = bus_unit_track_remove_sender ( u , message ) ;
if ( r = = - EUNATCH )
return sd_bus_error_setf ( error , BUS_ERROR_NOT_REFERENCED , " Unit has not been referenced yet. " ) ;
if ( r < 0 )
return r ;
return sd_bus_reply_method_return ( message , NULL ) ;
}
2018-10-08 15:44:22 +02:00
static int property_get_refs (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
Unit * u = userdata ;
const char * i ;
int r ;
assert ( bus ) ;
assert ( reply ) ;
r = sd_bus_message_open_container ( reply , ' a ' , " s " ) ;
if ( r < 0 )
return r ;
for ( i = sd_bus_track_first ( u - > bus_track ) ; i ; i = sd_bus_track_next ( u - > bus_track ) ) {
int c , k ;
c = sd_bus_track_count_name ( u - > bus_track , i ) ;
if ( c < 0 )
return c ;
/* Add the item multiple times if the ref count for each is above 1 */
for ( k = 0 ; k < c ; k + + ) {
r = sd_bus_message_append ( reply , " s " , i ) ;
if ( r < 0 )
return r ;
}
}
return sd_bus_message_close_container ( reply ) ;
}
2013-11-19 21:12:59 +01:00
const sd_bus_vtable bus_unit_vtable [ ] = {
SD_BUS_VTABLE_START ( 0 ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " Id " , " s " , NULL , offsetof ( Unit , id ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2018-05-14 05:38:57 +02:00
SD_BUS_PROPERTY ( " Names " , " as " , property_get_names , offsetof ( Unit , names ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-11-19 21:12:59 +01:00
SD_BUS_PROPERTY ( " Following " , " s " , property_get_following , 0 , 0 ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " Requires " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_REQUIRES ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " Requisite " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_REQUISITE ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " Wants " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_WANTS ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " BindsTo " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_BINDS_TO ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " PartOf " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_PART_OF ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " RequiredBy " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_REQUIRED_BY ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2015-05-19 01:24:28 +02:00
SD_BUS_PROPERTY ( " RequisiteOf " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_REQUISITE_OF ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " WantedBy " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_WANTED_BY ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " BoundBy " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_BOUND_BY ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " ConsistsOf " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_CONSISTS_OF ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " Conflicts " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_CONFLICTS ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " ConflictedBy " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_CONFLICTED_BY ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " Before " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_BEFORE ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " After " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_AFTER ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " OnFailure " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_ON_FAILURE ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " Triggers " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_TRIGGERS ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " TriggeredBy " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_TRIGGERED_BY ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " PropagatesReloadTo " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_PROPAGATES_RELOAD_TO ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " ReloadPropagatedFrom " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_RELOAD_PROPAGATED_FROM ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " JoinsNamespaceOf " , " as " , property_get_dependencies , offsetof ( Unit , dependencies [ UNIT_JOINS_NAMESPACE_OF ] ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2017-11-14 09:01:21 +01:00
SD_BUS_PROPERTY ( " RequiresMountsFor " , " as " , property_get_requires_mounts_for , offsetof ( Unit , requires_mounts_for ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " Documentation " , " as " , NULL , offsetof ( Unit , documentation ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " Description " , " s " , property_get_description , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " LoadState " , " s " , property_get_load_state , offsetof ( Unit , load_state ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-11-19 21:12:59 +01:00
SD_BUS_PROPERTY ( " ActiveState " , " s " , property_get_active_state , 0 , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
SD_BUS_PROPERTY ( " SubState " , " s " , property_get_sub_state , 0 , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " FragmentPath " , " s " , NULL , offsetof ( Unit , fragment_path ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " SourcePath " , " s " , NULL , offsetof ( Unit , source_path ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " DropInPaths " , " as " , NULL , offsetof ( Unit , dropin_paths ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-11-19 21:12:59 +01:00
SD_BUS_PROPERTY ( " UnitFileState " , " s " , property_get_unit_file_state , 0 , 0 ) ,
2014-12-02 02:38:18 +01:00
SD_BUS_PROPERTY ( " UnitFilePreset " , " s " , property_get_unit_file_preset , 0 , 0 ) ,
2016-02-01 16:01:25 +01:00
BUS_PROPERTY_DUAL_TIMESTAMP ( " StateChangeTimestamp " , offsetof ( Unit , state_change_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2013-11-19 21:12:59 +01:00
BUS_PROPERTY_DUAL_TIMESTAMP ( " InactiveExitTimestamp " , offsetof ( Unit , inactive_exit_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
BUS_PROPERTY_DUAL_TIMESTAMP ( " ActiveEnterTimestamp " , offsetof ( Unit , active_enter_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
BUS_PROPERTY_DUAL_TIMESTAMP ( " ActiveExitTimestamp " , offsetof ( Unit , active_exit_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
BUS_PROPERTY_DUAL_TIMESTAMP ( " InactiveEnterTimestamp " , offsetof ( Unit , inactive_enter_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " CanStart " , " b " , property_get_can_start , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " CanStop " , " b " , property_get_can_stop , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " CanReload " , " b " , property_get_can_reload , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " CanIsolate " , " b " , property_get_can_isolate , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2018-05-14 05:38:57 +02:00
SD_BUS_PROPERTY ( " Job " , " (uo) " , property_get_job , offsetof ( Unit , job ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " StopWhenUnneeded " , " b " , bus_property_get_bool , offsetof ( Unit , stop_when_unneeded ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " RefuseManualStart " , " b " , bus_property_get_bool , offsetof ( Unit , refuse_manual_start ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " RefuseManualStop " , " b " , bus_property_get_bool , offsetof ( Unit , refuse_manual_stop ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " AllowIsolate " , " b " , bus_property_get_bool , offsetof ( Unit , allow_isolate ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " DefaultDependencies " , " b " , bus_property_get_bool , offsetof ( Unit , default_dependencies ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " OnFailureJobMode " , " s " , property_get_job_mode , offsetof ( Unit , on_failure_job_mode ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " IgnoreOnIsolate " , " b " , bus_property_get_bool , offsetof ( Unit , ignore_on_isolate ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " NeedDaemonReload " , " b " , property_get_need_daemon_reload , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
SD_BUS_PROPERTY ( " JobTimeoutUSec " , " t " , bus_property_get_usec , offsetof ( Unit , job_timeout ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2017-02-17 17:47:20 +01:00
SD_BUS_PROPERTY ( " JobRunningTimeoutUSec " , " t " , bus_property_get_usec , offsetof ( Unit , job_running_timeout ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2016-10-20 15:27:37 +02:00
SD_BUS_PROPERTY ( " JobTimeoutAction " , " s " , property_get_emergency_action , offsetof ( Unit , job_timeout_action ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2014-10-28 01:49:07 +01:00
SD_BUS_PROPERTY ( " JobTimeoutRebootArgument " , " s " , NULL , offsetof ( Unit , job_timeout_reboot_arg ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-11-19 21:12:59 +01:00
SD_BUS_PROPERTY ( " ConditionResult " , " b " , bus_property_get_bool , offsetof ( Unit , condition_result ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2014-11-06 13:43:45 +01:00
SD_BUS_PROPERTY ( " AssertResult " , " b " , bus_property_get_bool , offsetof ( Unit , assert_result ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2013-11-19 21:12:59 +01:00
BUS_PROPERTY_DUAL_TIMESTAMP ( " ConditionTimestamp " , offsetof ( Unit , condition_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2014-11-06 13:43:45 +01:00
BUS_PROPERTY_DUAL_TIMESTAMP ( " AssertTimestamp " , offsetof ( Unit , assert_timestamp ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2018-11-29 16:34:59 +01:00
SD_BUS_PROPERTY ( " Conditions " , " a(sbbsi) " , property_get_conditions , offsetof ( Unit , conditions ) , SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION ) ,
SD_BUS_PROPERTY ( " Asserts " , " a(sbbsi) " , property_get_conditions , offsetof ( Unit , asserts ) , SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION ) ,
2018-06-01 17:32:54 +02:00
SD_BUS_PROPERTY ( " LoadError " , " (ss) " , property_get_load_error , 0 , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-12-22 02:24:05 +01:00
SD_BUS_PROPERTY ( " Transient " , " b " , bus_property_get_bool , offsetof ( Unit , transient ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2016-10-24 21:41:54 +02:00
SD_BUS_PROPERTY ( " Perpetual " , " b " , bus_property_get_bool , offsetof ( Unit , perpetual ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2017-12-29 09:13:23 +01:00
SD_BUS_PROPERTY ( " StartLimitIntervalUSec " , " t " , bus_property_get_usec , offsetof ( Unit , start_limit . interval ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
core: make the StartLimitXYZ= settings generic and apply to any kind of unit, not just services
This moves the StartLimitBurst=, StartLimitInterval=, StartLimitAction=, RebootArgument= from the [Service] section
into the [Unit] section of unit files, and thus support it in all unit types, not just in services.
This way we can enforce the start limit much earlier, in particular before testing the unit conditions, so that
repeated start-up failure due to failed conditions is also considered for the start limit logic.
For compatibility the four options may also be configured in the [Service] section still, but we only document them in
their new section [Unit].
This also renamed the socket unit failure code "service-failed-permanent" into "service-start-limit-hit" to express
more clearly what it is about, after all it's only triggered through the start limit being hit.
Finally, the code in busname_trigger_notify() and socket_trigger_notify() is altered to become more alike.
Fixes: #2467
2016-02-09 18:38:03 +01:00
SD_BUS_PROPERTY ( " StartLimitBurst " , " u " , bus_property_get_unsigned , offsetof ( Unit , start_limit . burst ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2016-10-20 15:27:37 +02:00
SD_BUS_PROPERTY ( " StartLimitAction " , " s " , property_get_emergency_action , offsetof ( Unit , start_limit_action ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2017-11-16 15:02:56 +01:00
SD_BUS_PROPERTY ( " FailureAction " , " s " , property_get_emergency_action , offsetof ( Unit , failure_action ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2018-11-16 11:41:18 +01:00
SD_BUS_PROPERTY ( " FailureActionExitStatus " , " i " , bus_property_get_int , offsetof ( Unit , failure_action_exit_status ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2017-11-16 15:18:01 +01:00
SD_BUS_PROPERTY ( " SuccessAction " , " s " , property_get_emergency_action , offsetof ( Unit , success_action ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2018-11-16 11:41:18 +01:00
SD_BUS_PROPERTY ( " SuccessActionExitStatus " , " i " , bus_property_get_int , offsetof ( Unit , success_action_exit_status ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
core: make the StartLimitXYZ= settings generic and apply to any kind of unit, not just services
This moves the StartLimitBurst=, StartLimitInterval=, StartLimitAction=, RebootArgument= from the [Service] section
into the [Unit] section of unit files, and thus support it in all unit types, not just in services.
This way we can enforce the start limit much earlier, in particular before testing the unit conditions, so that
repeated start-up failure due to failed conditions is also considered for the start limit logic.
For compatibility the four options may also be configured in the [Service] section still, but we only document them in
their new section [Unit].
This also renamed the socket unit failure code "service-failed-permanent" into "service-start-limit-hit" to express
more clearly what it is about, after all it's only triggered through the start limit being hit.
Finally, the code in busname_trigger_notify() and socket_trigger_notify() is altered to become more alike.
Fixes: #2467
2016-02-09 18:38:03 +01:00
SD_BUS_PROPERTY ( " RebootArgument " , " s " , NULL , offsetof ( Unit , reboot_arg ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2018-11-29 16:39:18 +01:00
SD_BUS_PROPERTY ( " InvocationID " , " ay " , bus_property_get_id128 , offsetof ( Unit , invocation_id ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2018-11-29 16:40:13 +01:00
SD_BUS_PROPERTY ( " CollectMode " , " s " , property_get_collect_mode , offsetof ( Unit , collect_mode ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2018-10-08 15:44:22 +02:00
SD_BUS_PROPERTY ( " Refs " , " as " , property_get_refs , 0 , 0 ) ,
2013-11-19 21:12:59 +01:00
2015-02-18 17:40:57 +01:00
SD_BUS_METHOD ( " Start " , " s " , " o " , method_start , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " Stop " , " s " , " o " , method_stop , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " Reload " , " s " , " o " , method_reload , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " Restart " , " s " , " o " , method_restart , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " TryRestart " , " s " , " o " , method_try_restart , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " ReloadOrRestart " , " s " , " o " , method_reload_or_restart , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " ReloadOrTryRestart " , " s " , " o " , method_reload_or_try_restart , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2019-03-22 20:57:30 +01:00
SD_BUS_METHOD ( " EnqueueJob " , " ss " , " uososa(uosos) " , bus_unit_method_enqueue_job , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2015-02-18 17:40:57 +01:00
SD_BUS_METHOD ( " Kill " , " si " , NULL , bus_unit_method_kill , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " ResetFailed " , NULL , NULL , bus_unit_method_reset_failed , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " SetProperties " , " ba(sv) " , NULL , bus_unit_method_set_properties , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2016-08-15 18:12:01 +02:00
SD_BUS_METHOD ( " Ref " , NULL , NULL , bus_unit_method_ref , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " Unref " , NULL , NULL , bus_unit_method_unref , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2013-11-19 21:12:59 +01:00
2018-05-14 03:07:00 +02:00
/* For dependency types we don't support anymore always return an empty array */
SD_BUS_PROPERTY ( " RequiresOverridable " , " as " , property_get_empty_strv , 0 , SD_BUS_VTABLE_HIDDEN ) ,
SD_BUS_PROPERTY ( " RequisiteOverridable " , " as " , property_get_empty_strv , 0 , SD_BUS_VTABLE_HIDDEN ) ,
SD_BUS_PROPERTY ( " RequiredByOverridable " , " as " , property_get_empty_strv , 0 , SD_BUS_VTABLE_HIDDEN ) ,
SD_BUS_PROPERTY ( " RequisiteOfOverridable " , " as " , property_get_empty_strv , 0 , SD_BUS_VTABLE_HIDDEN ) ,
/* Obsolete alias names */
2016-08-01 17:40:37 +02:00
SD_BUS_PROPERTY ( " StartLimitInterval " , " t " , bus_property_get_usec , offsetof ( Unit , start_limit . interval ) , SD_BUS_VTABLE_PROPERTY_CONST | SD_BUS_VTABLE_HIDDEN ) ,
2017-12-29 09:13:23 +01:00
SD_BUS_PROPERTY ( " StartLimitIntervalSec " , " t " , bus_property_get_usec , offsetof ( Unit , start_limit . interval ) , SD_BUS_VTABLE_PROPERTY_CONST | SD_BUS_VTABLE_HIDDEN ) ,
2013-11-19 21:12:59 +01:00
SD_BUS_VTABLE_END
} ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
static int property_get_slice (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
2013-11-21 19:34:37 +01:00
void * userdata ,
sd_bus_error * error ) {
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
Unit * u = userdata ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( reply ) ;
assert ( u ) ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
return sd_bus_message_append ( reply , " s " , unit_slice_name ( u ) ) ;
}
2010-10-13 03:03:31 +02:00
2015-01-23 02:58:02 +01:00
static int property_get_current_memory (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
uint64_t sz = ( uint64_t ) - 1 ;
2015-03-01 16:24:19 +01:00
Unit * u = userdata ;
2015-01-23 02:58:02 +01:00
int r ;
assert ( bus ) ;
assert ( reply ) ;
assert ( u ) ;
2015-03-01 16:24:19 +01:00
r = unit_get_memory_current ( u , & sz ) ;
if ( r < 0 & & r ! = - ENODATA )
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
log_unit_warning_errno ( u , r , " Failed to get memory.usage_in_bytes attribute: %m " ) ;
2015-01-23 02:58:02 +01:00
2015-03-01 16:24:19 +01:00
return sd_bus_message_append ( reply , " t " , sz ) ;
}
2015-01-23 02:58:02 +01:00
2015-09-10 12:32:16 +02:00
static int property_get_current_tasks (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
uint64_t cn = ( uint64_t ) - 1 ;
Unit * u = userdata ;
int r ;
assert ( bus ) ;
assert ( reply ) ;
assert ( u ) ;
r = unit_get_tasks_current ( u , & cn ) ;
if ( r < 0 & & r ! = - ENODATA )
log_unit_warning_errno ( u , r , " Failed to get pids.current attribute: %m " ) ;
return sd_bus_message_append ( reply , " t " , cn ) ;
}
2015-03-01 16:24:19 +01:00
static int property_get_cpu_usage (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
2015-01-23 02:58:02 +01:00
2015-03-01 16:24:19 +01:00
nsec_t ns = ( nsec_t ) - 1 ;
Unit * u = userdata ;
int r ;
assert ( bus ) ;
assert ( reply ) ;
assert ( u ) ;
r = unit_get_cpu_usage ( u , & ns ) ;
if ( r < 0 & & r ! = - ENODATA )
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
log_unit_warning_errno ( u , r , " Failed to get cpuacct.usage attribute: %m " ) ;
2015-03-01 16:24:19 +01:00
return sd_bus_message_append ( reply , " t " , ns ) ;
2015-01-23 02:58:02 +01:00
}
2015-08-25 20:42:50 +02:00
static int property_get_cgroup (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
Unit * u = userdata ;
2018-05-10 18:22:49 +02:00
const char * t = NULL ;
2015-08-25 20:42:50 +02:00
assert ( bus ) ;
assert ( reply ) ;
assert ( u ) ;
/* Three cases: a) u->cgroup_path is NULL, in which case the
* unit has no control group , which we report as the empty
* string . b ) u - > cgroup_path is the empty string , which
* indicates the root cgroup , which we report as " / " . c ) all
* other cases we report as - is . */
if ( u - > cgroup_path )
2018-05-10 18:47:33 +02:00
t = empty_to_root ( u - > cgroup_path ) ;
2015-08-25 20:42:50 +02:00
return sd_bus_message_append ( reply , " s " , t ) ;
}
2016-04-20 15:28:28 +02:00
static int append_process ( sd_bus_message * reply , const char * p , pid_t pid , Set * pids ) {
_cleanup_free_ char * buf = NULL , * cmdline = NULL ;
int r ;
assert ( reply ) ;
assert ( pid > 0 ) ;
r = set_put ( pids , PID_TO_PTR ( pid ) ) ;
2017-10-04 16:01:32 +02:00
if ( IN_SET ( r , 0 , - EEXIST ) )
2016-04-20 15:28:28 +02:00
return 0 ;
if ( r < 0 )
return r ;
if ( ! p ) {
r = cg_pid_get_path ( SYSTEMD_CGROUP_CONTROLLER , pid , & buf ) ;
if ( r = = - ESRCH )
return 0 ;
if ( r < 0 )
return r ;
p = buf ;
}
( void ) get_process_cmdline ( pid , 0 , true , & cmdline ) ;
return sd_bus_message_append ( reply ,
" (sus) " ,
p ,
( uint32_t ) pid ,
cmdline ) ;
}
static int append_cgroup ( sd_bus_message * reply , const char * p , Set * pids ) {
_cleanup_closedir_ DIR * d = NULL ;
_cleanup_fclose_ FILE * f = NULL ;
int r ;
assert ( reply ) ;
assert ( p ) ;
r = cg_enumerate_processes ( SYSTEMD_CGROUP_CONTROLLER , p , & f ) ;
2018-06-06 20:22:41 +02:00
if ( r = = - ENOENT )
2016-04-20 15:28:28 +02:00
return 0 ;
if ( r < 0 )
return r ;
for ( ; ; ) {
pid_t pid ;
r = cg_read_pid ( f , & pid ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
if ( is_kernel_thread ( pid ) > 0 )
continue ;
r = append_process ( reply , p , pid , pids ) ;
if ( r < 0 )
return r ;
}
r = cg_enumerate_subgroups ( SYSTEMD_CGROUP_CONTROLLER , p , & d ) ;
if ( r = = - ENOENT )
return 0 ;
if ( r < 0 )
return r ;
for ( ; ; ) {
_cleanup_free_ char * g = NULL , * j = NULL ;
r = cg_read_subgroup ( d , & g ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
2016-10-23 17:43:27 +02:00
j = strjoin ( p , " / " , g ) ;
2016-04-20 15:28:28 +02:00
if ( ! j )
return - ENOMEM ;
r = append_cgroup ( reply , j , pids ) ;
if ( r < 0 )
return r ;
}
return 0 ;
}
int bus_unit_method_get_processes ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * reply = NULL ;
2018-05-14 07:13:57 +02:00
_cleanup_set_free_ Set * pids = NULL ;
2016-04-20 15:28:28 +02:00
Unit * u = userdata ;
pid_t pid ;
int r ;
assert ( message ) ;
2017-02-10 11:54:18 +01:00
r = mac_selinux_unit_access_check ( u , message , " status " , error ) ;
if ( r < 0 )
return r ;
2016-04-20 15:28:28 +02:00
pids = set_new ( NULL ) ;
if ( ! pids )
return - ENOMEM ;
r = sd_bus_message_new_method_return ( message , & reply ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_open_container ( reply , ' a ' , " (sus) " ) ;
if ( r < 0 )
return r ;
if ( u - > cgroup_path ) {
r = append_cgroup ( reply , u - > cgroup_path , pids ) ;
if ( r < 0 )
return r ;
}
/* The main and control pids might live outside of the cgroup, hence fetch them separately */
pid = unit_main_pid ( u ) ;
if ( pid > 0 ) {
r = append_process ( reply , NULL , pid , pids ) ;
if ( r < 0 )
return r ;
}
pid = unit_control_pid ( u ) ;
if ( pid > 0 ) {
r = append_process ( reply , NULL , pid , pids ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_close_container ( reply ) ;
if ( r < 0 )
return r ;
return sd_bus_send ( NULL , reply , NULL ) ;
}
2017-09-05 19:27:53 +02:00
static int property_get_ip_counter (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
2019-03-22 11:47:29 +01:00
static const char * const table [ _CGROUP_IP_ACCOUNTING_METRIC_MAX ] = {
[ CGROUP_IP_INGRESS_BYTES ] = " IPIngressBytes " ,
[ CGROUP_IP_EGRESS_BYTES ] = " IPEgressBytes " ,
[ CGROUP_IP_INGRESS_PACKETS ] = " IPIngressPackets " ,
[ CGROUP_IP_EGRESS_PACKETS ] = " IPEgressPackets " ,
} ;
uint64_t value = UINT64_MAX ;
2017-09-05 19:27:53 +02:00
Unit * u = userdata ;
2019-03-22 11:47:29 +01:00
ssize_t metric ;
2017-09-05 19:27:53 +02:00
assert ( bus ) ;
assert ( reply ) ;
assert ( property ) ;
assert ( u ) ;
2019-03-22 11:47:29 +01:00
assert_se ( ( metric = string_table_lookup ( table , ELEMENTSOF ( table ) , property ) ) > = 0 ) ;
2017-09-05 19:27:53 +02:00
( void ) unit_get_ip_accounting ( u , metric , & value ) ;
return sd_bus_message_append ( reply , " t " , value ) ;
}
2019-03-22 12:16:03 +01:00
static int property_get_io_counter (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
static const char * const table [ _CGROUP_IO_ACCOUNTING_METRIC_MAX ] = {
[ CGROUP_IO_READ_BYTES ] = " IOReadBytes " ,
[ CGROUP_IO_WRITE_BYTES ] = " IOWriteBytes " ,
[ CGROUP_IO_READ_OPERATIONS ] = " IOReadOperations " ,
[ CGROUP_IO_WRITE_OPERATIONS ] = " IOWriteOperations " ,
} ;
uint64_t value = UINT64_MAX ;
Unit * u = userdata ;
ssize_t metric ;
assert ( bus ) ;
assert ( reply ) ;
assert ( property ) ;
assert ( u ) ;
assert_se ( ( metric = string_table_lookup ( table , ELEMENTSOF ( table ) , property ) ) > = 0 ) ;
( void ) unit_get_io_accounting ( u , metric , false , & value ) ;
return sd_bus_message_append ( reply , " t " , value ) ;
}
2018-02-07 22:52:52 +01:00
int bus_unit_method_attach_processes ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
_cleanup_ ( sd_bus_creds_unrefp ) sd_bus_creds * creds = NULL ;
2018-05-14 07:13:57 +02:00
_cleanup_set_free_ Set * pids = NULL ;
2018-02-07 22:52:52 +01:00
Unit * u = userdata ;
const char * path ;
int r ;
assert ( message ) ;
/* This migrates the processes with the specified PIDs into the cgroup of this unit, optionally below a
* specified cgroup path . Obviously this only works for units that actually maintain a cgroup
* representation . If a process is already in the cgroup no operation is executed – in this case the specified
* subcgroup path has no effect ! */
r = mac_selinux_unit_access_check ( u , message , " start " , error ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_read ( message , " s " , & path ) ;
if ( r < 0 )
return r ;
path = empty_to_null ( path ) ;
if ( path ) {
if ( ! path_is_absolute ( path ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Control group path is not absolute: %s " , path ) ;
if ( ! path_is_normalized ( path ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Control group path is not normalized: %s " , path ) ;
}
if ( ! unit_cgroup_delegate ( u ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Process migration not available on non-delegated units. " ) ;
if ( UNIT_IS_INACTIVE_OR_FAILED ( unit_active_state ( u ) ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Unit is not active, refusing. " ) ;
r = sd_bus_query_sender_creds ( message , SD_BUS_CREDS_EUID | SD_BUS_CREDS_PID , & creds ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_enter_container ( message , ' a ' , " u " ) ;
if ( r < 0 )
return r ;
for ( ; ; ) {
uid_t process_uid , sender_uid ;
uint32_t upid ;
pid_t pid ;
r = sd_bus_message_read ( message , " u " , & upid ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
if ( upid = = 0 ) {
r = sd_bus_creds_get_pid ( creds , & pid ) ;
if ( r < 0 )
return r ;
} else
pid = ( uid_t ) upid ;
/* Filter out duplicates */
if ( set_contains ( pids , PID_TO_PTR ( pid ) ) )
continue ;
/* Check if this process is suitable for attaching to this unit */
r = unit_pid_attachable ( u , pid , error ) ;
if ( r < 0 )
return r ;
/* Let's query the sender's UID, so that we can make our security decisions */
r = sd_bus_creds_get_euid ( creds , & sender_uid ) ;
if ( r < 0 )
return r ;
2018-06-27 20:02:49 +02:00
/* Let's validate security: if the sender is root, then all is OK. If the sender is any other unit,
2018-02-07 22:52:52 +01:00
* then the process ' UID and the target unit ' s UID have to match the sender ' s UID */
if ( sender_uid ! = 0 & & sender_uid ! = getuid ( ) ) {
r = get_process_uid ( pid , & process_uid ) ;
if ( r < 0 )
return sd_bus_error_set_errnof ( error , r , " Failed to retrieve process UID: %m " ) ;
if ( process_uid ! = sender_uid )
return sd_bus_error_setf ( error , SD_BUS_ERROR_ACCESS_DENIED , " Process " PID_FMT " not owned by client's UID. Refusing. " , pid ) ;
if ( process_uid ! = u - > ref_uid )
return sd_bus_error_setf ( error , SD_BUS_ERROR_ACCESS_DENIED , " Process " PID_FMT " not owned by target unit's UID. Refusing. " , pid ) ;
}
if ( ! pids ) {
pids = set_new ( NULL ) ;
if ( ! pids )
return - ENOMEM ;
}
r = set_put ( pids , PID_TO_PTR ( pid ) ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_exit_container ( message ) ;
if ( r < 0 )
return r ;
r = unit_attach_pids_to_cgroup ( u , pids , path ) ;
if ( r < 0 )
return sd_bus_error_set_errnof ( error , r , " Failed to attach processes to control group: %m " ) ;
return sd_bus_reply_method_return ( message , NULL ) ;
}
2013-11-19 21:12:59 +01:00
const sd_bus_vtable bus_unit_cgroup_vtable [ ] = {
SD_BUS_VTABLE_START ( 0 ) ,
SD_BUS_PROPERTY ( " Slice " , " s " , property_get_slice , 0 , 0 ) ,
2015-08-25 20:42:50 +02:00
SD_BUS_PROPERTY ( " ControlGroup " , " s " , property_get_cgroup , 0 , 0 ) ,
2015-01-23 02:58:02 +01:00
SD_BUS_PROPERTY ( " MemoryCurrent " , " t " , property_get_current_memory , 0 , 0 ) ,
2015-03-01 16:24:19 +01:00
SD_BUS_PROPERTY ( " CPUUsageNSec " , " t " , property_get_cpu_usage , 0 , 0 ) ,
2015-09-10 12:32:16 +02:00
SD_BUS_PROPERTY ( " TasksCurrent " , " t " , property_get_current_tasks , 0 , 0 ) ,
2017-09-05 19:27:53 +02:00
SD_BUS_PROPERTY ( " IPIngressBytes " , " t " , property_get_ip_counter , 0 , 0 ) ,
SD_BUS_PROPERTY ( " IPIngressPackets " , " t " , property_get_ip_counter , 0 , 0 ) ,
SD_BUS_PROPERTY ( " IPEgressBytes " , " t " , property_get_ip_counter , 0 , 0 ) ,
SD_BUS_PROPERTY ( " IPEgressPackets " , " t " , property_get_ip_counter , 0 , 0 ) ,
2019-03-22 12:16:03 +01:00
SD_BUS_PROPERTY ( " IOReadBytes " , " t " , property_get_io_counter , 0 , 0 ) ,
SD_BUS_PROPERTY ( " IOReadOperations " , " t " , property_get_io_counter , 0 , 0 ) ,
SD_BUS_PROPERTY ( " IOWriteBytes " , " t " , property_get_io_counter , 0 , 0 ) ,
SD_BUS_PROPERTY ( " IOWriteOperations " , " t " , property_get_io_counter , 0 , 0 ) ,
2016-04-20 15:28:28 +02:00
SD_BUS_METHOD ( " GetProcesses " , NULL , " a(sus) " , bus_unit_method_get_processes , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2018-02-07 22:52:52 +01:00
SD_BUS_METHOD ( " AttachProcesses " , " sau " , NULL , bus_unit_method_attach_processes , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2013-11-19 21:12:59 +01:00
SD_BUS_VTABLE_END
} ;
2010-10-13 03:03:31 +02:00
2014-03-03 01:33:45 +01:00
static int send_new_signal ( sd_bus * bus , void * userdata ) {
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * m = NULL ;
2013-11-19 21:12:59 +01:00
_cleanup_free_ char * p = NULL ;
Unit * u = userdata ;
int r ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( u ) ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
p = unit_dbus_path ( u ) ;
2015-05-19 06:45:52 +02:00
if ( ! p )
2013-11-19 21:12:59 +01:00
return - ENOMEM ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_new_signal (
bus ,
2014-02-19 23:54:58 +01:00
& m ,
2013-11-19 21:12:59 +01:00
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2014-02-19 23:54:58 +01:00
" UnitNew " ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
return r ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_append ( m , " so " , u - > id , p ) ;
if ( r < 0 )
return r ;
2010-10-13 03:03:31 +02:00
2014-03-03 01:33:45 +01:00
return sd_bus_send ( bus , m , NULL ) ;
2013-11-19 21:12:59 +01:00
}
2010-10-13 03:03:31 +02:00
2014-03-03 01:33:45 +01:00
static int send_changed_signal ( sd_bus * bus , void * userdata ) {
2013-11-19 21:12:59 +01:00
_cleanup_free_ char * p = NULL ;
Unit * u = userdata ;
int r ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( u ) ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
p = unit_dbus_path ( u ) ;
2014-01-31 17:47:22 +01:00
if ( ! p )
2013-11-19 21:12:59 +01:00
return - ENOMEM ;
2010-10-13 03:03:31 +02:00
2013-11-19 21:12:59 +01:00
/* Send a properties changed signal. First for the specific
* type , then for the generic unit . The clients may rely on
* this order to get atomic behavior if needed . */
2010-02-01 03:33:24 +01:00
2013-12-22 03:43:03 +01:00
r = sd_bus_emit_properties_changed_strv (
bus , p ,
2015-08-27 22:30:43 +02:00
unit_dbus_interface_from_type ( u - > type ) ,
2013-12-22 03:43:03 +01:00
NULL ) ;
2014-03-11 04:10:19 +01:00
if ( r < 0 )
2013-12-22 03:43:03 +01:00
return r ;
2012-05-21 12:54:34 +02:00
2014-03-11 04:10:19 +01:00
return sd_bus_emit_properties_changed_strv (
2013-11-19 21:12:59 +01:00
bus , p ,
" org.freedesktop.systemd1.Unit " ,
NULL ) ;
2010-02-01 03:33:24 +01:00
}
2010-02-05 00:38:41 +01:00
void bus_unit_send_change_signal ( Unit * u ) {
2013-07-10 20:33:11 +02:00
int r ;
2010-02-05 00:38:41 +01:00
assert ( u ) ;
2012-01-15 12:04:08 +01:00
if ( u - > in_dbus_queue ) {
2013-10-14 06:10:14 +02:00
LIST_REMOVE ( dbus_queue , u - > manager - > dbus_unit_queue , u ) ;
2012-01-15 12:04:08 +01:00
u - > in_dbus_queue = false ;
2010-07-11 03:59:49 +02:00
}
2010-02-05 00:38:41 +01:00
2012-01-15 12:04:08 +01:00
if ( ! u - > id )
2010-08-09 17:02:09 +02:00
return ;
2017-02-28 17:55:57 +01:00
r = bus_foreach_bus ( u - > manager , u - > bus_track , u - > sent_dbus_new_signal ? send_changed_signal : send_new_signal , u ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
log_unit_debug_errno ( u , r , " Failed to send unit change signal for %s: %m " , u - > id ) ;
2010-02-05 00:38:41 +01:00
2013-11-19 21:12:59 +01:00
u - > sent_dbus_new_signal = true ;
}
2010-08-20 02:26:05 +02:00
2018-11-27 20:15:45 +01:00
void bus_unit_send_pending_change_signal ( Unit * u , bool including_new ) {
/* Sends out any pending change signals, but only if they really are pending. This call is used when we are
* about to change state in order to force out a PropertiesChanged signal beforehand if there was one pending
* so that clients can follow the full state transition */
if ( ! u - > in_dbus_queue ) /* If not enqueued, don't bother */
return ;
if ( ! u - > sent_dbus_new_signal & & ! including_new ) /* If the unit was never announced, don't bother, it's fine if
* the unit appears in the new state right - away ( except if the
* caller explicitly asked us to send it anyway ) */
return ;
if ( MANAGER_IS_RELOADING ( u - > manager ) ) /* Don't generate unnecessary PropertiesChanged signals for the same unit
* when we are reloading . */
return ;
bus_unit_send_change_signal ( u ) ;
}
2014-03-03 01:33:45 +01:00
static int send_removed_signal ( sd_bus * bus , void * userdata ) {
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * m = NULL ;
2013-11-19 21:12:59 +01:00
_cleanup_free_ char * p = NULL ;
Unit * u = userdata ;
int r ;
2010-08-20 02:26:05 +02:00
2013-11-19 21:12:59 +01:00
assert ( bus ) ;
assert ( u ) ;
2010-02-05 00:38:41 +01:00
2013-11-19 21:12:59 +01:00
p = unit_dbus_path ( u ) ;
2015-05-19 06:45:52 +02:00
if ( ! p )
2013-11-19 21:12:59 +01:00
return - ENOMEM ;
2010-02-05 00:38:41 +01:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_new_signal (
bus ,
2014-02-19 23:54:58 +01:00
& m ,
2013-11-19 21:12:59 +01:00
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2014-02-19 23:54:58 +01:00
" UnitRemoved " ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
return r ;
2010-02-05 00:38:41 +01:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_append ( m , " so " , u - > id , p ) ;
if ( r < 0 )
return r ;
2010-02-05 00:38:41 +01:00
2014-03-03 01:33:45 +01:00
return sd_bus_send ( bus , m , NULL ) ;
2010-02-05 00:38:41 +01:00
}
void bus_unit_send_removed_signal ( Unit * u ) {
2013-11-19 21:12:59 +01:00
int r ;
2010-02-05 00:38:41 +01:00
assert ( u ) ;
2016-09-09 17:05:06 +02:00
if ( ! u - > sent_dbus_new_signal | | u - > in_dbus_queue )
2010-05-22 04:27:24 +02:00
bus_unit_send_change_signal ( u ) ;
2012-01-15 12:04:08 +01:00
if ( ! u - > id )
2010-08-09 17:02:09 +02:00
return ;
2017-02-28 17:55:57 +01:00
r = bus_foreach_bus ( u - > manager , u - > bus_track , send_removed_signal , u ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
log_unit_debug_errno ( u , r , " Failed to send unit remove signal for %s: %m " , u - > id ) ;
2010-02-05 00:38:41 +01:00
}
2012-01-17 09:20:32 +01:00
2013-11-19 21:12:59 +01:00
int bus_unit_queue_job (
sd_bus_message * message ,
2012-10-02 23:07:00 +02:00
Unit * u ,
JobType type ,
JobMode mode ,
2019-03-22 20:57:30 +01:00
BusUnitQueueFlags flags ,
2013-11-21 19:34:37 +01:00
sd_bus_error * error ) {
2012-10-02 23:07:00 +02:00
2019-03-22 20:57:30 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * reply = NULL ;
_cleanup_free_ char * job_path = NULL , * unit_path = NULL ;
_cleanup_ ( set_freep ) Set * affected = NULL ;
Iterator i ;
Job * j , * a ;
2012-10-02 23:07:00 +02:00
int r ;
assert ( message ) ;
assert ( u ) ;
assert ( type > = 0 & & type < _JOB_TYPE_MAX ) ;
assert ( mode > = 0 & & mode < _JOB_MODE_MAX ) ;
2016-01-31 14:55:54 +01:00
r = mac_selinux_unit_access_check (
u , message ,
job_type_to_access_method ( type ) ,
error ) ;
if ( r < 0 )
return r ;
2019-03-22 20:57:30 +01:00
if ( FLAGS_SET ( flags , BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE ) & & unit_can_reload ( u ) ) {
2012-10-02 23:07:00 +02:00
if ( type = = JOB_RESTART )
type = JOB_RELOAD_OR_START ;
else if ( type = = JOB_TRY_RESTART )
2016-01-28 18:48:42 +01:00
type = JOB_TRY_RELOAD ;
2012-10-02 23:07:00 +02:00
}
2013-11-19 21:12:59 +01:00
if ( type = = JOB_STOP & &
2018-06-01 17:46:01 +02:00
IN_SET ( u - > load_state , UNIT_NOT_FOUND , UNIT_ERROR , UNIT_BAD_SETTING ) & &
2013-11-19 21:12:59 +01:00
unit_active_state ( u ) = = UNIT_INACTIVE )
2013-11-21 19:34:37 +01:00
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_UNIT , " Unit %s not loaded. " , u - > id ) ;
2012-10-02 23:07:00 +02:00
if ( ( type = = JOB_START & & u - > refuse_manual_start ) | |
( type = = JOB_STOP & & u - > refuse_manual_stop ) | |
2017-09-29 00:37:23 +02:00
( IN_SET ( type , JOB_RESTART , JOB_TRY_RESTART ) & & ( u - > refuse_manual_start | | u - > refuse_manual_stop ) ) | |
2015-10-26 05:23:09 +01:00
( type = = JOB_RELOAD_OR_START & & job_type_collapse ( type , u ) = = JOB_START & & u - > refuse_manual_start ) )
2017-01-24 04:06:05 +01:00
return sd_bus_error_setf ( error , BUS_ERROR_ONLY_BY_DEPENDENCY , " Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop) . " , u->id) ;
2012-10-02 23:07:00 +02:00
2019-03-22 20:57:30 +01:00
if ( FLAGS_SET ( flags , BUS_UNIT_QUEUE_VERBOSE_REPLY ) ) {
affected = set_new ( NULL ) ;
if ( ! affected )
return - ENOMEM ;
}
r = manager_add_job ( u - > manager , type , u , mode , affected , error , & j ) ;
2012-10-02 23:07:00 +02:00
if ( r < 0 )
2013-11-21 19:34:37 +01:00
return r ;
2012-10-02 23:07:00 +02:00
2016-11-15 19:32:50 +01:00
r = bus_job_track_sender ( j , message ) ;
if ( r < 0 )
return r ;
2012-10-02 23:07:00 +02:00
2018-11-29 18:48:20 +01:00
/* Before we send the method reply, force out the announcement JobNew for this job */
bus_job_send_pending_change_signal ( j , true ) ;
2019-03-22 20:57:30 +01:00
job_path = job_dbus_path ( j ) ;
if ( ! job_path )
return - ENOMEM ;
/* The classic response is just a job object path */
if ( ! FLAGS_SET ( flags , BUS_UNIT_QUEUE_VERBOSE_REPLY ) )
return sd_bus_reply_method_return ( message , " o " , job_path ) ;
/* In verbose mode respond with the anchor job plus everything that has been affected */
r = sd_bus_message_new_method_return ( message , & reply ) ;
if ( r < 0 )
return r ;
unit_path = unit_dbus_path ( j - > unit ) ;
if ( ! unit_path )
return - ENOMEM ;
r = sd_bus_message_append ( reply , " uosos " ,
j - > id , job_path ,
j - > unit - > id , unit_path ,
job_type_to_string ( j - > type ) ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_open_container ( reply , ' a ' , " (uosos) " ) ;
if ( r < 0 )
return r ;
SET_FOREACH ( a , affected , i ) {
if ( a - > id = = j - > id )
continue ;
/* Free paths from previous iteration */
job_path = mfree ( job_path ) ;
unit_path = mfree ( unit_path ) ;
job_path = job_dbus_path ( a ) ;
if ( ! job_path )
return - ENOMEM ;
unit_path = unit_dbus_path ( a - > unit ) ;
if ( ! unit_path )
return - ENOMEM ;
r = sd_bus_message_append ( reply , " (uosos) " ,
a - > id , job_path ,
a - > unit - > id , unit_path ,
job_type_to_string ( a - > type ) ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_close_container ( reply ) ;
if ( r < 0 )
return r ;
return sd_bus_send ( NULL , reply , NULL ) ;
2012-10-02 23:07:00 +02:00
}
2017-11-22 16:34:56 +01:00
static int bus_unit_set_live_property (
2013-07-01 00:40:56 +02:00
Unit * u ,
const char * name ,
2013-11-19 21:12:59 +01:00
sd_bus_message * message ,
2017-11-22 15:03:51 +01:00
UnitWriteFlags flags ,
2013-11-19 21:12:59 +01:00
sd_bus_error * error ) {
2013-07-01 00:40:56 +02:00
int r ;
assert ( u ) ;
assert ( name ) ;
2013-11-19 21:12:59 +01:00
assert ( message ) ;
2013-07-01 00:40:56 +02:00
2017-11-22 16:34:56 +01:00
/* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for transient
* units that are being created ) . */
2013-07-01 00:40:56 +02:00
if ( streq ( name , " Description " ) ) {
2013-11-19 21:12:59 +01:00
const char * d ;
2013-07-01 00:40:56 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_read ( message , " s " , & d ) ;
if ( r < 0 )
return r ;
2013-07-02 15:49:27 +02:00
2017-11-22 15:03:51 +01:00
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
2013-11-19 21:12:59 +01:00
r = unit_set_description ( u , d ) ;
2013-07-02 15:49:27 +02:00
if ( r < 0 )
return r ;
2013-07-10 21:13:56 +02:00
2017-11-22 15:03:51 +01:00
unit_write_settingf ( u , flags | UNIT_ESCAPE_SPECIFIERS , name , " Description=%s " , d ) ;
2013-07-02 15:49:27 +02:00
}
2013-07-01 00:40:56 +02:00
return 1 ;
2017-11-22 16:34:56 +01:00
}
return 0 ;
}
2018-10-16 13:28:39 +02:00
static int bus_set_transient_emergency_action (
Unit * u ,
const char * name ,
EmergencyAction * p ,
sd_bus_message * message ,
UnitWriteFlags flags ,
sd_bus_error * error ) {
const char * s ;
EmergencyAction v ;
int r ;
bool system ;
assert ( p ) ;
r = sd_bus_message_read ( message , " s " , & s ) ;
if ( r < 0 )
return r ;
system = MANAGER_IS_SYSTEM ( u - > manager ) ;
r = parse_emergency_action ( s , system , & v ) ;
core: Fix return argument check for parse_emergency_action
This function returns 0 on success and a negative value on failure. On success,
it writes the parsed action to the address passed in its third argument.
`bus_set_transient_emergency_action` does this:
r = parse_emergency_action(s, system, &v);
if (v < 0)
// handle failure
However, `v` is not updated if the function fails, and this should be checking
`r` instead of `v`.
The result of this is that if an invalid failure (or success) action is
specified, systemd ends up creating the unit anyway and then misbehaves if it
tries to run the failure action because the action value comes from
uninitialized stack data. In my case, this resulted in a failed assertion:
Program received signal SIGABRT, Aborted.
0x00007fe52cca0d7f in raise () from /snap/usr/lib/libc.so.6
(gdb) bt
#0 0x00007fe52cca0d7f in raise () from /snap/usr/lib/libc.so.6
#1 0x00007fe52cc8b672 in abort () from /snap/usr/lib/libc.so.6
#2 0x00007fe52d66f169 in log_assert_failed_realm (realm=LOG_REALM_SYSTEMD, text=0x56177ab8e000 "action < _EMERGENCY_ACTION_MAX", file=0x56177ab8dfb8 "../src/core/emergency-action.c", line=33, func=0x56177ab8e2b0 <__PRETTY_FUNCTION__.14207> "emergency_action") at ../src/basic/log.c:795
#3 0x000056177aa98cf4 in emergency_action (m=0x56177c992cb0, action=2059118610, options=(unknown: 0), reboot_arg=0x0, exit_status=1, reason=0x7ffdd2df4290 "unit run-u0.service failed") at ../src/core/emergency-action.c:33
#4 0x000056177ab2b739 in unit_notify (u=0x56177c9eb340, os=UNIT_ACTIVE, ns=UNIT_FAILED, flags=(unknown: 0)) at ../src/core/unit.c:2504
#5 0x000056177aaf62ed in service_set_state (s=0x56177c9eb340, state=SERVICE_FAILED) at ../src/core/service.c:1104
#6 0x000056177aaf8a29 in service_enter_dead (s=0x56177c9eb340, f=SERVICE_SUCCESS, allow_restart=true) at ../src/core/service.c:1712
#7 0x000056177aaf9233 in service_enter_signal (s=0x56177c9eb340, state=SERVICE_FINAL_SIGKILL, f=SERVICE_SUCCESS) at ../src/core/service.c:1854
#8 0x000056177aaf921b in service_enter_signal (s=0x56177c9eb340, state=SERVICE_FINAL_SIGTERM, f=SERVICE_SUCCESS) at ../src/core/service.c:1852
#9 0x000056177aaf8eb3 in service_enter_stop_post (s=0x56177c9eb340, f=SERVICE_SUCCESS) at ../src/core/service.c:1788
#10 0x000056177aaf91eb in service_enter_signal (s=0x56177c9eb340, state=SERVICE_STOP_SIGKILL, f=SERVICE_SUCCESS) at ../src/core/service.c:1850
#11 0x000056177aaf91bc in service_enter_signal (s=0x56177c9eb340, state=SERVICE_STOP_SIGTERM, f=SERVICE_FAILURE_EXIT_CODE) at ../src/core/service.c:1848
#12 0x000056177aaf9759 in service_enter_running (s=0x56177c9eb340, f=SERVICE_FAILURE_EXIT_CODE) at ../src/core/service.c:1941
#13 0x000056177ab005b7 in service_sigchld_event (u=0x56177c9eb340, pid=112, code=1, status=1) at ../src/core/service.c:3296
#14 0x000056177aad84b5 in manager_invoke_sigchld_event (m=0x56177c992cb0, u=0x56177c9eb340, si=0x7ffdd2df48f0) at ../src/core/manager.c:2444
#15 0x000056177aad88df in manager_dispatch_sigchld (source=0x56177c994710, userdata=0x56177c992cb0) at ../src/core/manager.c:2508
#16 0x00007fe52d72f807 in source_dispatch (s=0x56177c994710) at ../src/libsystemd/sd-event/sd-event.c:2846
#17 0x00007fe52d730f7d in sd_event_dispatch (e=0x56177c993530) at ../src/libsystemd/sd-event/sd-event.c:3229
#18 0x00007fe52d73142e in sd_event_run (e=0x56177c993530, timeout=18446744073709551615) at ../src/libsystemd/sd-event/sd-event.c:3286
#19 0x000056177aad9f71 in manager_loop (m=0x56177c992cb0) at ../src/core/manager.c:2906
#20 0x000056177aa7c876 in invoke_main_loop (m=0x56177c992cb0, ret_reexecute=0x7ffdd2df4bff, ret_retval=0x7ffdd2df4c04, ret_shutdown_verb=0x7ffdd2df4c58, ret_fds=0x7ffdd2df4c70, ret_switch_root_dir=0x7ffdd2df4c48, ret_switch_root_init=0x7ffdd2df4c50, ret_error_message=0x7ffdd2df4c60) at ../src/core/main.c:1792
#21 0x000056177aa7f251 in main (argc=2, argv=0x7ffdd2df4e78) at ../src/core/main.c:2573
Fix this by checking the correct variable.
2019-01-16 19:00:21 +01:00
if ( r < 0 )
2018-10-16 13:28:39 +02:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS ,
2019-01-16 19:26:15 +01:00
r = = - EOPNOTSUPP ? " %s setting invalid for manager type: %s "
2018-10-16 13:28:39 +02:00
: " Invalid %s setting: %s " ,
name , s ) ;
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
* p = v ;
unit_write_settingf ( u , flags , name ,
" %s=%s " , name , s ) ;
}
return 1 ;
}
2018-11-16 11:41:18 +01:00
static int bus_set_transient_exit_status (
Unit * u ,
const char * name ,
int * p ,
sd_bus_message * message ,
UnitWriteFlags flags ,
sd_bus_error * error ) {
int32_t k ;
int r ;
assert ( p ) ;
r = sd_bus_message_read ( message , " i " , & k ) ;
if ( r < 0 )
return r ;
if ( k > 255 )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Exit status must be in range 0…255 or negative. " ) ;
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
* p = k < 0 ? - 1 : k ;
if ( k < 0 )
unit_write_settingf ( u , flags , name , " %s= " , name ) ;
else
unit_write_settingf ( u , flags , name , " %s=%i " , name , k ) ;
}
return 1 ;
}
2018-01-01 16:26:34 +01:00
static BUS_DEFINE_SET_TRANSIENT_PARSE ( collect_mode , CollectMode , collect_mode_from_string ) ;
static BUS_DEFINE_SET_TRANSIENT_PARSE ( job_mode , JobMode , job_mode_from_string ) ;
static int bus_set_transient_conditions (
Unit * u ,
const char * name ,
Condition * * list ,
bool is_condition ,
sd_bus_message * message ,
UnitWriteFlags flags ,
sd_bus_error * error ) {
const char * type_name , * param ;
int trigger , negate , r ;
bool empty = true ;
assert ( list ) ;
r = sd_bus_message_enter_container ( message , ' a ' , " (sbbs) " ) ;
if ( r < 0 )
return r ;
while ( ( r = sd_bus_message_read ( message , " (sbbs) " , & type_name , & trigger , & negate , & param ) ) > 0 ) {
ConditionType t ;
t = is_condition ? condition_type_from_string ( type_name ) : assert_type_from_string ( type_name ) ;
if ( t < 0 )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Invalid condition type: %s " , type_name ) ;
if ( t ! = CONDITION_NULL ) {
if ( isempty ( param ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Condition parameter in %s is empty " , type_name ) ;
if ( condition_takes_path ( t ) & & ! path_is_absolute ( param ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Path in condition %s is not absolute: %s " , type_name , param ) ;
} else
param = NULL ;
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
Condition * c ;
c = condition_new ( t , param , trigger , negate ) ;
if ( ! c )
return - ENOMEM ;
LIST_PREPEND ( conditions , * list , c ) ;
if ( t ! = CONDITION_NULL )
unit_write_settingf ( u , flags | UNIT_ESCAPE_SPECIFIERS , name ,
" %s=%s%s%s " , type_name ,
trigger ? " | " : " " , negate ? " ! " : " " , param ) ;
else
unit_write_settingf ( u , flags , name ,
" %s=%s%s " , type_name ,
trigger ? " | " : " " , yes_no ( ! negate ) ) ;
}
empty = false ;
}
if ( r < 0 )
return r ;
r = sd_bus_message_exit_container ( message ) ;
if ( r < 0 )
return r ;
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) & & empty ) {
* list = condition_free_list ( * list ) ;
unit_write_settingf ( u , flags , name , " %sNull= " , is_condition ? " Condition " : " Assert " ) ;
}
return 1 ;
}
2017-11-22 16:34:56 +01:00
static int bus_unit_set_transient_property (
Unit * u ,
const char * name ,
sd_bus_message * message ,
UnitWriteFlags flags ,
sd_bus_error * error ) {
2018-01-01 16:26:34 +01:00
UnitDependency d = _UNIT_DEPENDENCY_INVALID ;
2017-11-22 16:34:56 +01:00
int r ;
2015-02-03 19:07:40 +01:00
2017-11-22 16:34:56 +01:00
assert ( u ) ;
assert ( name ) ;
assert ( message ) ;
/* Handles settings when transient units are created. This settings cannot be altered anymore after the unit
* has been created . */
2018-01-01 16:26:34 +01:00
if ( streq ( name , " SourcePath " ) )
return bus_set_transient_path ( u , name , & u - > source_path , message , flags , error ) ;
2015-02-03 19:07:40 +01:00
2018-01-01 16:26:34 +01:00
if ( streq ( name , " StopWhenUnneeded " ) )
return bus_set_transient_bool ( u , name , & u - > stop_when_unneeded , message , flags , error ) ;
2015-02-03 19:07:40 +01:00
2018-01-01 16:26:34 +01:00
if ( streq ( name , " RefuseManualStart " ) )
return bus_set_transient_bool ( u , name , & u - > refuse_manual_start , message , flags , error ) ;
2015-02-03 19:07:40 +01:00
2018-01-01 16:26:34 +01:00
if ( streq ( name , " RefuseManualStop " ) )
return bus_set_transient_bool ( u , name , & u - > refuse_manual_stop , message , flags , error ) ;
2013-07-01 03:02:42 +02:00
2018-01-01 16:26:34 +01:00
if ( streq ( name , " AllowIsolate " ) )
return bus_set_transient_bool ( u , name , & u - > allow_isolate , message , flags , error ) ;
2017-11-13 17:14:07 +01:00
2018-01-01 16:26:34 +01:00
if ( streq ( name , " DefaultDependencies " ) )
return bus_set_transient_bool ( u , name , & u - > default_dependencies , message , flags , error ) ;
if ( streq ( name , " OnFailureJobMode " ) )
return bus_set_transient_job_mode ( u , name , & u - > on_failure_job_mode , message , flags , error ) ;
if ( streq ( name , " IgnoreOnIsolate " ) )
return bus_set_transient_bool ( u , name , & u - > ignore_on_isolate , message , flags , error ) ;
if ( streq ( name , " JobTimeoutUSec " ) ) {
r = bus_set_transient_usec_fix_0 ( u , name , & u - > job_timeout , message , flags , error ) ;
if ( r > = 0 & & ! UNIT_WRITE_FLAGS_NOOP ( flags ) & & ! u - > job_running_timeout_set )
u - > job_running_timeout = u - > job_timeout ;
}
if ( streq ( name , " JobRunningTimeoutUSec " ) ) {
r = bus_set_transient_usec_fix_0 ( u , name , & u - > job_running_timeout , message , flags , error ) ;
if ( r > = 0 & & ! UNIT_WRITE_FLAGS_NOOP ( flags ) )
u - > job_running_timeout_set = true ;
return r ;
}
if ( streq ( name , " JobTimeoutAction " ) )
return bus_set_transient_emergency_action ( u , name , & u - > job_timeout_action , message , flags , error ) ;
if ( streq ( name , " JobTimeoutRebootArgument " ) )
return bus_set_transient_string ( u , name , & u - > job_timeout_reboot_arg , message , flags , error ) ;
if ( streq ( name , " StartLimitIntervalUSec " ) )
return bus_set_transient_usec ( u , name , & u - > start_limit . interval , message , flags , error ) ;
if ( streq ( name , " StartLimitBurst " ) )
return bus_set_transient_unsigned ( u , name , & u - > start_limit . burst , message , flags , error ) ;
if ( streq ( name , " StartLimitAction " ) )
return bus_set_transient_emergency_action ( u , name , & u - > start_limit_action , message , flags , error ) ;
if ( streq ( name , " FailureAction " ) )
return bus_set_transient_emergency_action ( u , name , & u - > failure_action , message , flags , error ) ;
if ( streq ( name , " SuccessAction " ) )
return bus_set_transient_emergency_action ( u , name , & u - > success_action , message , flags , error ) ;
2018-11-16 11:41:18 +01:00
if ( streq ( name , " FailureActionExitStatus " ) )
return bus_set_transient_exit_status ( u , name , & u - > failure_action_exit_status , message , flags , error ) ;
if ( streq ( name , " SuccessActionExitStatus " ) )
return bus_set_transient_exit_status ( u , name , & u - > success_action_exit_status , message , flags , error ) ;
2018-01-01 16:26:34 +01:00
if ( streq ( name , " RebootArgument " ) )
return bus_set_transient_string ( u , name , & u - > reboot_arg , message , flags , error ) ;
if ( streq ( name , " CollectMode " ) )
return bus_set_transient_collect_mode ( u , name , & u - > collect_mode , message , flags , error ) ;
if ( streq ( name , " Conditions " ) )
return bus_set_transient_conditions ( u , name , & u - > conditions , true , message , flags , error ) ;
if ( streq ( name , " Asserts " ) )
return bus_set_transient_conditions ( u , name , & u - > asserts , false , message , flags , error ) ;
if ( streq ( name , " Documentation " ) ) {
_cleanup_strv_free_ char * * l = NULL ;
char * * p ;
r = sd_bus_message_read_strv ( message , & l ) ;
2017-11-13 17:14:07 +01:00
if ( r < 0 )
return r ;
2018-01-01 16:26:34 +01:00
STRV_FOREACH ( p , l ) {
if ( ! documentation_url_is_valid ( * p ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Invalid URL in %s: %s " , name , * p ) ;
}
2017-11-13 17:14:07 +01:00
2017-11-22 15:03:51 +01:00
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
2018-01-01 16:26:34 +01:00
if ( strv_isempty ( l ) ) {
u - > documentation = strv_free ( u - > documentation ) ;
unit_write_settingf ( u , flags , name , " %s= " , name ) ;
} else {
strv_extend_strv ( & u - > documentation , l , false ) ;
STRV_FOREACH ( p , l )
unit_write_settingf ( u , flags , name , " %s=%s " , name , * p ) ;
}
2017-11-13 17:14:07 +01:00
}
return 1 ;
2015-08-28 17:36:39 +02:00
} else if ( streq ( name , " Slice " ) ) {
Unit * slice ;
2013-07-01 03:02:42 +02:00
const char * s ;
2015-08-28 17:36:39 +02:00
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. " ) ;
core: unified cgroup hierarchy support
This patch set adds full support the new unified cgroup hierarchy logic
of modern kernels.
A new kernel command line option "systemd.unified_cgroup_hierarchy=1" is
added. If specified the unified hierarchy is mounted to /sys/fs/cgroup
instead of a tmpfs. No further hierarchies are mounted. The kernel
command line option defaults to off. We can turn it on by default as
soon as the kernel's APIs regarding this are stabilized (but even then
downstream distros might want to turn this off, as this will break any
tools that access cgroupfs directly).
It is possibly to choose for each boot individually whether the unified
or the legacy hierarchy is used. nspawn will by default provide the
legacy hierarchy to containers if the host is using it, and the unified
otherwise. However it is possible to run containers with the unified
hierarchy on a legacy host and vice versa, by setting the
$UNIFIED_CGROUP_HIERARCHY environment variable for nspawn to 1 or 0,
respectively.
The unified hierarchy provides reliable cgroup empty notifications for
the first time, via inotify. To make use of this we maintain one
manager-wide inotify fd, and each cgroup to it.
This patch also removes cg_delete() which is unused now.
On kernel 4.2 only the "memory" controller is compatible with the
unified hierarchy, hence that's the only controller systemd exposes when
booted in unified heirarchy mode.
This introduces a new enum for enumerating supported controllers, plus a
related enum for the mask bits mapping to it. The core is changed to
make use of this everywhere.
This moves PID 1 into a new "init.scope" implicit scope unit in the root
slice. This is necessary since on the unified hierarchy cgroups may
either contain subgroups or processes but not both. PID 1 hence has to
move out of the root cgroup (strictly speaking the root cgroup is the
only one where processes and subgroups are still allowed, but in order
to support containers nicey, we move PID 1 into the new scope in all
cases.) This new unit is also used on legacy hierarchy setups. It's
actually pretty useful on all systems, as it can then be used to filter
journal messages coming from PID 1, and so on.
The root slice ("-.slice") is now implicitly created and started (and
does not require a unit file on disk anymore), since
that's where "init.scope" is located and the slice needs to be started
before the scope can.
To check whether we are in unified or legacy hierarchy mode we use
statfs() on /sys/fs/cgroup. If the .f_type field reports tmpfs we are in
legacy mode, if it reports cgroupfs we are in unified mode.
This patch set carefuly makes sure that cgls and cgtop continue to work
as desired.
When invoking nspawn as a service it will implicitly create two
subcgroups in the cgroup it is using, one to move the nspawn process
into, the other to move the actual container processes into. This is
done because of the requirement that cgroups may either contain
processes or other subgroups.
2015-09-01 19:22:36 +02:00
if ( unit_has_name ( u , SPECIAL_INIT_SCOPE ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Cannot set slice for init.scope " ) ;
2015-08-28 17:36:39 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_read ( message , " s " , & s ) ;
if ( r < 0 )
return r ;
2013-07-01 03:02:42 +02:00
2015-08-28 17:36:39 +02:00
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 ) ;
2016-04-22 17:30:08 +02:00
/* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be
* loaded while we are still setting it up . Or in other words , we use manager_load_unit_prepare ( )
* instead of manager_load_unit ( ) on purpose , here . */
r = manager_load_unit_prepare ( u - > manager , s , NULL , error , & slice ) ;
2015-08-28 17:36:39 +02:00
if ( r < 0 )
return r ;
2013-07-01 03:02:42 +02:00
2015-08-28 17:36:39 +02:00
if ( slice - > type ! = UNIT_SLICE )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Unit name '%s' is not a slice " , s ) ;
2013-07-10 21:13:56 +02:00
2017-11-22 15:03:51 +01:00
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
2015-08-28 17:36:39 +02:00
r = unit_set_slice ( u , slice ) ;
2013-07-02 15:49:27 +02:00
if ( r < 0 )
return r ;
2013-07-01 03:02:42 +02:00
2017-11-22 15:03:51 +01:00
unit_write_settingf ( u , flags | UNIT_PRIVATE , name , " Slice=%s " , s ) ;
2013-07-02 15:49:27 +02:00
}
2013-07-11 21:29:33 +02:00
2013-07-01 03:02:42 +02:00
return 1 ;
2015-08-28 17:36:39 +02:00
2018-01-01 16:26:34 +01:00
} else if ( streq ( name , " RequiresMountsFor " ) ) {
_cleanup_strv_free_ char * * l = NULL ;
char * * p ;
r = sd_bus_message_read_strv ( message , & l ) ;
if ( r < 0 )
return r ;
STRV_FOREACH ( p , l ) {
2019-03-07 07:12:10 +01:00
path_simplify ( * p , true ) ;
2018-01-01 16:26:34 +01:00
if ( ! path_is_absolute ( * p ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Path specified in %s is not absolute: %s " , name , * p ) ;
2019-03-07 07:12:10 +01:00
if ( ! path_is_valid ( * p ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Path specified in %s has invalid length: %s " , name , * p ) ;
if ( ! path_is_normalized ( * p ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Path specified in %s is not normalized: %s " , name , * p ) ;
2018-01-01 16:26:34 +01:00
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
r = unit_require_mounts_for ( u , * p , UNIT_DEPENDENCY_FILE ) ;
if ( r < 0 )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Failed to add required mount \" %s \" : %m " , * p ) ;
2013-07-10 23:39:46 +02:00
2018-01-01 16:26:34 +01:00
unit_write_settingf ( u , flags , name , " %s=%s " , name , * p ) ;
}
2015-11-12 19:21:47 +01:00
}
2013-07-10 23:39:46 +02:00
2018-01-01 16:26:34 +01:00
return 1 ;
}
if ( streq ( name , " RequiresOverridable " ) )
d = UNIT_REQUIRES ; /* redirect for obsolete unit dependency type */
else if ( streq ( name , " RequisiteOverridable " ) )
d = UNIT_REQUISITE ; /* same here */
else
d = unit_dependency_from_string ( name ) ;
if ( d > = 0 ) {
const char * other ;
2013-11-19 21:12:59 +01:00
r = sd_bus_message_enter_container ( message , ' a ' , " s " ) ;
if ( r < 0 )
return r ;
2013-07-10 23:39:46 +02:00
2013-11-19 21:12:59 +01:00
while ( ( r = sd_bus_message_read ( message , " s " , & other ) ) > 0 ) {
2015-04-30 20:21:00 +02:00
if ( ! unit_name_is_valid ( other , UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE ) )
2013-11-19 21:12:59 +01:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Invalid unit name %s " , other ) ;
2013-07-10 23:39:46 +02:00
2017-11-22 15:03:51 +01:00
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) ) {
2013-07-11 21:29:33 +02:00
_cleanup_free_ char * label = NULL ;
2013-07-10 23:39:46 +02:00
2018-09-15 19:57:52 +02:00
r = unit_add_dependency_by_name ( u , d , other , true , UNIT_DEPENDENCY_FILE ) ;
2013-07-10 23:39:46 +02:00
if ( r < 0 )
return r ;
2016-10-23 17:43:27 +02:00
label = strjoin ( name , " - " , other ) ;
2013-07-10 23:39:46 +02:00
if ( ! label )
return - ENOMEM ;
2018-01-01 16:26:34 +01:00
unit_write_settingf ( u , flags , label , " %s=%s " , unit_dependency_to_string ( d ) , other ) ;
2013-07-10 23:39:46 +02:00
}
}
2013-11-19 21:12:59 +01:00
if ( r < 0 )
return r ;
2013-07-10 23:39:46 +02:00
2013-11-21 20:49:04 +01:00
r = sd_bus_message_exit_container ( message ) ;
if ( r < 0 )
return r ;
2013-07-10 23:39:46 +02:00
return 1 ;
2016-08-15 18:12:01 +02:00
} else if ( streq ( name , " AddRef " ) ) {
int b ;
/* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method
* on the Unit interface , and it ' s probably not a good idea to expose a property and a method on the
* same interface ( well , strictly speaking AddRef isn ' t exposed as full property , we just read it for
* transient units , but still ) . And " References " and " ReferencedBy " is already used as unit reference
* dependency type , hence let ' s not confuse things with that .
*
* Note that we don ' t acually add the reference to the bus track . We do that only after the setup of
* the transient unit is complete , so that setting this property multiple times in the same transient
* unit creation call doesn ' t count as individual references . */
r = sd_bus_message_read ( message , " b " , & b ) ;
if ( r < 0 )
return r ;
2017-11-22 15:03:51 +01:00
if ( ! UNIT_WRITE_FLAGS_NOOP ( flags ) )
2016-08-15 18:12:01 +02:00
u - > bus_track_add = b ;
return 1 ;
2013-07-01 00:40:56 +02:00
}
return 0 ;
}
2013-06-28 04:12:58 +02:00
int bus_unit_set_properties (
Unit * u ,
2013-11-19 21:12:59 +01:00
sd_bus_message * message ,
2017-11-22 15:03:51 +01:00
UnitWriteFlags flags ,
2013-06-28 04:12:58 +02:00
bool commit ,
2013-11-19 21:12:59 +01:00
sd_bus_error * error ) {
2013-06-28 04:12:58 +02:00
2013-06-27 21:14:56 +02:00
bool for_real = false ;
unsigned n = 0 ;
int r ;
assert ( u ) ;
2013-11-19 21:12:59 +01:00
assert ( message ) ;
2013-06-27 21:14:56 +02:00
/* We iterate through the array twice. First run we just check
* if all passed data is valid , second run actually applies
* it . This is to implement transaction - like behaviour without
* actually providing full transactions . */
2013-11-19 21:12:59 +01:00
r = sd_bus_message_enter_container ( message , ' a ' , " (sv) " ) ;
if ( r < 0 )
return r ;
2013-06-27 21:14:56 +02:00
for ( ; ; ) {
const char * name ;
2017-11-22 15:03:51 +01:00
UnitWriteFlags f ;
2013-06-27 21:14:56 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_enter_container ( message , ' r ' , " sv " ) ;
if ( r < 0 )
return r ;
if ( r = = 0 ) {
2017-11-22 15:03:51 +01:00
if ( for_real | | UNIT_WRITE_FLAGS_NOOP ( flags ) )
2013-06-27 21:14:56 +02:00
break ;
/* Reached EOF. Let's try again, and this time for realz... */
2013-11-19 21:12:59 +01:00
r = sd_bus_message_rewind ( message , false ) ;
if ( r < 0 )
return r ;
2013-11-21 20:49:04 +01:00
2013-06-27 21:14:56 +02:00
for_real = true ;
continue ;
}
2013-11-19 21:12:59 +01:00
r = sd_bus_message_read ( message , " s " , & name ) ;
if ( r < 0 )
return r ;
2013-06-27 21:14:56 +02:00
2013-11-19 21:12:59 +01:00
if ( ! UNIT_VTABLE ( u ) - > bus_set_property )
return sd_bus_error_setf ( error , SD_BUS_ERROR_PROPERTY_READ_ONLY , " Objects of this type do not support setting properties. " ) ;
2013-06-27 21:14:56 +02:00
2013-11-19 21:12:59 +01:00
r = sd_bus_message_enter_container ( message , ' v ' , NULL ) ;
if ( r < 0 )
return r ;
2013-06-27 21:14:56 +02:00
2017-11-22 15:03:51 +01:00
/* If not for real, then mask out the two target flags */
f = for_real ? flags : ( flags & ~ ( UNIT_RUNTIME | UNIT_PERSISTENT ) ) ;
r = UNIT_VTABLE ( u ) - > bus_set_property ( u , name , message , f , error ) ;
2013-07-01 00:40:56 +02:00
if ( r = = 0 & & u - > transient & & u - > load_state = = UNIT_STUB )
2017-11-22 15:03:51 +01:00
r = bus_unit_set_transient_property ( u , name , message , f , error ) ;
2017-11-22 16:34:56 +01:00
if ( r = = 0 )
r = bus_unit_set_live_property ( u , name , message , f , error ) ;
2013-11-19 21:12:59 +01:00
if ( r < 0 )
return r ;
2017-11-22 16:34:56 +01:00
2013-11-19 21:12:59 +01:00
if ( r = = 0 )
return sd_bus_error_setf ( error , SD_BUS_ERROR_PROPERTY_READ_ONLY , " Cannot set property %s, or unknown property. " , name ) ;
r = sd_bus_message_exit_container ( message ) ;
2013-06-27 21:14:56 +02:00
if ( r < 0 )
return r ;
2013-11-19 21:12:59 +01:00
r = sd_bus_message_exit_container ( message ) ;
if ( r < 0 )
return r ;
2013-06-27 21:14:56 +02:00
n + = for_real ;
}
2013-11-21 20:49:04 +01:00
r = sd_bus_message_exit_container ( message ) ;
if ( r < 0 )
return r ;
2013-06-28 04:12:58 +02:00
if ( commit & & n > 0 & & UNIT_VTABLE ( u ) - > bus_commit_properties )
2013-06-27 21:14:56 +02:00
UNIT_VTABLE ( u ) - > bus_commit_properties ( u ) ;
2013-06-28 00:41:24 +02:00
return n ;
2013-06-27 21:14:56 +02:00
}
2015-11-13 14:12:19 +01:00
2018-06-01 17:30:43 +02:00
int bus_unit_validate_load_state ( Unit * u , sd_bus_error * error ) {
2016-04-08 11:27:28 +02:00
assert ( u ) ;
2015-11-13 14:12:19 +01:00
2018-06-01 17:30:43 +02:00
/* Generates a pretty error if a unit isn't properly loaded. */
2015-11-13 14:12:19 +01:00
2018-06-01 17:30:43 +02:00
switch ( u - > load_state ) {
case UNIT_LOADED :
return 0 ;
2015-11-13 14:12:19 +01:00
2018-06-01 17:30:43 +02:00
case UNIT_NOT_FOUND :
2016-02-09 20:47:45 +01:00
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_UNIT , " Unit %s not found. " , u - > id ) ;
2015-11-13 14:12:19 +01:00
2018-06-01 17:46:01 +02:00
case UNIT_BAD_SETTING :
return sd_bus_error_setf ( error , BUS_ERROR_BAD_UNIT_SETTING , " Unit %s has a bad unit file setting. " , u - > id ) ;
2018-06-01 17:30:43 +02:00
case UNIT_ERROR : /* Only show .load_error in UNIT_ERROR state */
2018-07-08 17:25:07 +02:00
return sd_bus_error_set_errnof ( error , u - > load_error , " Unit %s failed to load properly: %m. " , u - > id ) ;
2018-06-01 17:30:43 +02:00
case UNIT_MASKED :
return sd_bus_error_setf ( error , BUS_ERROR_UNIT_MASKED , " Unit %s is masked. " , u - > id ) ;
case UNIT_STUB :
case UNIT_MERGED :
default :
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_UNIT , " Unexpected load state of unit %s " , u - > id ) ;
}
2015-11-13 14:12:19 +01:00
}
2016-08-15 18:12:01 +02:00
2016-11-15 19:32:50 +01:00
static int bus_unit_track_handler ( sd_bus_track * t , void * userdata ) {
2016-08-15 18:12:01 +02:00
Unit * u = userdata ;
assert ( t ) ;
assert ( u ) ;
u - > bus_track = sd_bus_track_unref ( u - > bus_track ) ; /* make sure we aren't called again */
2018-10-05 23:04:51 +02:00
/* If the client that tracks us disappeared, then there's reason to believe that the cgroup is empty now too,
* let ' s see */
unit_add_to_cgroup_empty_queue ( u ) ;
/* Also add the unit to the GC queue, after all if the client left it might be time to GC this unit */
2016-08-15 18:12:01 +02:00
unit_add_to_gc_queue ( u ) ;
2018-10-05 23:04:51 +02:00
2016-08-15 18:12:01 +02:00
return 0 ;
}
2016-11-15 19:32:50 +01:00
static int bus_unit_allocate_bus_track ( Unit * u ) {
2016-08-15 18:12:01 +02:00
int r ;
assert ( u ) ;
if ( u - > bus_track )
return 0 ;
2016-11-15 19:32:50 +01:00
r = sd_bus_track_new ( u - > manager - > api_bus , & u - > bus_track , bus_unit_track_handler , u ) ;
2016-08-15 18:12:01 +02:00
if ( r < 0 )
return r ;
r = sd_bus_track_set_recursive ( u - > bus_track , true ) ;
if ( r < 0 ) {
u - > bus_track = sd_bus_track_unref ( u - > bus_track ) ;
return r ;
}
return 0 ;
}
int bus_unit_track_add_name ( Unit * u , const char * name ) {
int r ;
assert ( u ) ;
2016-11-15 19:32:50 +01:00
r = bus_unit_allocate_bus_track ( u ) ;
2016-08-15 18:12:01 +02:00
if ( r < 0 )
return r ;
return sd_bus_track_add_name ( u - > bus_track , name ) ;
}
int bus_unit_track_add_sender ( Unit * u , sd_bus_message * m ) {
int r ;
assert ( u ) ;
2016-11-15 19:32:50 +01:00
r = bus_unit_allocate_bus_track ( u ) ;
2016-08-15 18:12:01 +02:00
if ( r < 0 )
return r ;
return sd_bus_track_add_sender ( u - > bus_track , m ) ;
}
int bus_unit_track_remove_sender ( Unit * u , sd_bus_message * m ) {
assert ( u ) ;
/* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
* error */
if ( ! u - > bus_track )
return - EUNATCH ;
return sd_bus_track_remove_sender ( u - > bus_track , m ) ;
}