chiark / gitweb /
event: implement quit handlers
[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 = 0;
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                         unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec=%lluus\n", (unsigned long long) t);
143                 }
144
145                 return 1;
146         }
147
148         return 0;
149 }
150
151 int bus_scope_set_property(
152                 Unit *u,
153                 const char *name,
154                 DBusMessageIter *i,
155                 UnitSetPropertiesMode mode,
156                 DBusError *error) {
157
158         Scope *s = SCOPE(u);
159         int r;
160
161         assert(name);
162         assert(u);
163         assert(i);
164
165         r = bus_cgroup_set_property(u, &s->cgroup_context, name, i, mode, error);
166         if (r != 0)
167                 return r;
168
169         if (u->load_state == UNIT_STUB) {
170                 /* While we are created we still accept PIDs */
171
172                 r = bus_scope_set_transient_property(s, name, i, mode, error);
173                 if (r != 0)
174                         return r;
175
176                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, i, mode, error);
177                 if (r != 0)
178                         return r;
179         }
180
181         return 0;
182 }
183
184 int bus_scope_commit_properties(Unit *u) {
185         assert(u);
186
187         unit_realize_cgroup(u);
188         return 0;
189 }