chiark / gitweb /
scope: make TimeoutStopUSec= settable for transient units
[elogind.git] / src / core / dbus-scope.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23
24 #include "dbus-unit.h"
25 #include "dbus-common.h"
26 #include "dbus-cgroup.h"
27 #include "dbus-kill.h"
28 #include "selinux-access.h"
29 #include "dbus-scope.h"
30
31 #define BUS_SCOPE_INTERFACE                                             \
32         " <interface name=\"org.freedesktop.systemd1.Scope\">\n"        \
33         BUS_UNIT_CGROUP_INTERFACE                                       \
34         "  <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
35         BUS_KILL_CONTEXT_INTERFACE                                      \
36         BUS_CGROUP_CONTEXT_INTERFACE                                    \
37         "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
38         " </interface>\n"
39
40 #define INTROSPECTION                                                   \
41         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
42         "<node>\n"                                                      \
43         BUS_UNIT_INTERFACE                                              \
44         BUS_SCOPE_INTERFACE                                             \
45         BUS_PROPERTIES_INTERFACE                                        \
46         BUS_PEER_INTERFACE                                              \
47         BUS_INTROSPECTABLE_INTERFACE                                    \
48         "</node>\n"
49
50 #define INTERFACES_LIST                              \
51         BUS_UNIT_INTERFACES_LIST                     \
52         "org.freedesktop.systemd1.Scope\0"
53
54 const char bus_scope_interface[] _introspect_("Scope") = BUS_SCOPE_INTERFACE;
55
56 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_scope_append_scope_result, scope_result, ScopeResult);
57
58 static const BusProperty bus_scope_properties[] = {
59         { "TimeoutStopUSec",        bus_property_append_usec,      "t", offsetof(Scope, timeout_stop_usec) },
60         { "Result",                 bus_scope_append_scope_result, "s", offsetof(Scope, result)            },
61         {}
62 };
63
64 DBusHandlerResult bus_scope_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
65         Scope *s = SCOPE(u);
66
67         const BusBoundProperties bps[] = {
68                 { "org.freedesktop.systemd1.Unit",  bus_unit_properties,           u },
69                 { "org.freedesktop.systemd1.Scope", bus_unit_cgroup_properties,    u },
70                 { "org.freedesktop.systemd1.Scope", bus_scope_properties,          s },
71                 { "org.freedesktop.systemd1.Scope", bus_cgroup_context_properties, &s->cgroup_context },
72                 { "org.freedesktop.systemd1.Scope", bus_kill_context_properties,   &s->kill_context   },
73                 {}
74         };
75
76         SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
77
78         return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
79 }
80
81 static int bus_scope_set_transient_property(
82                 Scope *s,
83                 const char *name,
84                 DBusMessageIter *i,
85                 UnitSetPropertiesMode mode,
86                 DBusError *error) {
87
88         int r;
89
90         assert(name);
91         assert(s);
92         assert(i);
93
94         if (streq(name, "PIDs")) {
95                 DBusMessageIter sub;
96                 unsigned n;
97
98                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY ||
99                     dbus_message_iter_get_element_type(i) != DBUS_TYPE_UINT32)
100                         return -EINVAL;
101
102                 r = set_ensure_allocated(&s->pids, trivial_hash_func, trivial_compare_func);
103                 if (r < 0)
104                         return r;
105
106                 dbus_message_iter_recurse(i, &sub);
107                 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32) {
108                         uint32_t pid;
109
110                         dbus_message_iter_get_basic(&sub, &pid);
111
112                         if (pid <= 1)
113                                 return -EINVAL;
114
115                         if (mode != UNIT_CHECK) {
116                                 r = set_put(s->pids, LONG_TO_PTR(pid));
117                                 if (r < 0 && r != -EEXIST)
118                                         return r;
119                         }
120
121                         dbus_message_iter_next(&sub);
122                         n++;
123                 }
124
125                 if (n <= 0)
126                         return -EINVAL;
127
128                 return 1;
129
130         } else if (streq(name, "TimeoutStopUSec")) {
131
132                 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
133                         return -EINVAL;
134
135                 if (mode != UNIT_CHECK) {
136                         uint64_t t;
137
138                         dbus_message_iter_get_basic(i, &t);
139
140                         s->timeout_stop_usec = t;
141                 }
142
143                 return 1;
144         }
145
146         return 0;
147 }
148
149 int bus_scope_set_property(
150                 Unit *u,
151                 const char *name,
152                 DBusMessageIter *i,
153                 UnitSetPropertiesMode mode,
154                 DBusError *error) {
155
156         Scope *s = SCOPE(u);
157         int r;
158
159         assert(name);
160         assert(u);
161         assert(i);
162
163         r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
164         if (r != 0)
165                 return r;
166
167         if (u->load_state == UNIT_STUB) {
168                 /* While we are created we still accept PIDs */
169
170                 r = bus_scope_set_transient_property(s, name, i, mode, error);
171                 if (r != 0)
172                         return r;
173         }
174
175         return 0;
176 }
177
178 int bus_scope_commit_properties(Unit *u) {
179         assert(u);
180
181         unit_realize_cgroup(u);
182         return 0;
183 }