]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-user-dbus.c
logind: port logind to libsystemd-bus
[thirdparty/systemd.git] / src / login / logind-user-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 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 #include <string.h>
24
25 #include "strv.h"
26 #include "bus-util.h"
27
28 #include "logind.h"
29 #include "logind-user.h"
30
31 static int property_get_display(
32 sd_bus *bus,
33 const char *path,
34 const char *interface,
35 const char *property,
36 sd_bus_message *reply,
37 sd_bus_error *error,
38 void *userdata) {
39
40 _cleanup_free_ char *p = NULL;
41 User *u = userdata;
42
43 assert(bus);
44 assert(reply);
45 assert(u);
46
47 p = u->display ? session_bus_path(u->display) : strdup("/");
48 if (!p)
49 return -ENOMEM;
50
51 return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p);
52 }
53
54 static int property_get_state(
55 sd_bus *bus,
56 const char *path,
57 const char *interface,
58 const char *property,
59 sd_bus_message *reply,
60 sd_bus_error *error,
61 void *userdata) {
62
63 User *u = userdata;
64
65 assert(bus);
66 assert(reply);
67 assert(u);
68
69 return sd_bus_message_append(reply, "s", user_state_to_string(user_get_state(u)));
70 }
71
72 static int property_get_sessions(
73 sd_bus *bus,
74 const char *path,
75 const char *interface,
76 const char *property,
77 sd_bus_message *reply,
78 sd_bus_error *error,
79 void *userdata) {
80
81 User *u = userdata;
82 Session *session;
83 int r;
84
85 assert(bus);
86 assert(reply);
87 assert(u);
88
89 r = sd_bus_message_open_container(reply, 'a', "(so)");
90 if (r < 0)
91 return r;
92
93 LIST_FOREACH(sessions_by_user, session, u->sessions) {
94 _cleanup_free_ char *p = NULL;
95
96 p = session_bus_path(session);
97 if (!p)
98 return -ENOMEM;
99
100 r = sd_bus_message_append(reply, "(so)", session->id, p);
101 if (r < 0)
102 return r;
103
104 }
105
106 r = sd_bus_message_close_container(reply);
107 if (r < 0)
108 return r;
109
110 return 1;
111 }
112
113 static int property_get_idle_hint(
114 sd_bus *bus,
115 const char *path,
116 const char *interface,
117 const char *property,
118 sd_bus_message *reply,
119 sd_bus_error *error,
120 void *userdata) {
121
122 User *u = userdata;
123
124 assert(bus);
125 assert(reply);
126 assert(u);
127
128 return sd_bus_message_append(reply, "b", user_get_idle_hint(u, NULL) > 0);
129 }
130
131 static int property_get_idle_since_hint(
132 sd_bus *bus,
133 const char *path,
134 const char *interface,
135 const char *property,
136 sd_bus_message *reply,
137 sd_bus_error *error,
138 void *userdata) {
139
140 User *u = userdata;
141 dual_timestamp t;
142 uint64_t k;
143
144 assert(bus);
145 assert(reply);
146 assert(u);
147
148 user_get_idle_hint(u, &t);
149 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
150
151 return sd_bus_message_append(reply, "t", k);
152 }
153
154 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata) {
155 User *u = userdata;
156 int r;
157
158 assert(bus);
159 assert(message);
160 assert(u);
161
162 r = user_stop(u);
163 if (r < 0)
164 return sd_bus_reply_method_errno(bus, message, r, NULL);
165
166 return sd_bus_reply_method_return(bus, message, NULL);
167 }
168
169 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata) {
170 User *u = userdata;
171 int32_t signo;
172 int r;
173
174 assert(bus);
175 assert(message);
176 assert(u);
177
178 r = sd_bus_message_read(message, "i", &signo);
179 if (r < 0)
180 return sd_bus_reply_method_errno(bus, message, r, NULL);
181
182 if (signo <= 0 || signo >= _NSIG)
183 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
184
185 r = user_kill(u, signo);
186 if (r < 0)
187 return sd_bus_reply_method_errno(bus, message, r, NULL);
188
189 return sd_bus_reply_method_return(bus, message, NULL);
190 }
191
192 const sd_bus_vtable user_vtable[] = {
193 SD_BUS_VTABLE_START(0),
194
195 SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(User, uid), 0),
196 SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(User, gid), 0),
197 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(User, name), 0),
198 SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(User, timestamp.realtime), 0),
199 SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(User, timestamp.monotonic), 0),
200 SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), 0),
201 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), 0),
202 SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), 0),
203 SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, 0),
204 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
205 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
206 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
207 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
208 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
209
210 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
211 SD_BUS_METHOD("Kill", "i", NULL, method_kill, 0),
212
213 SD_BUS_VTABLE_END
214 };
215
216 int user_object_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
217
218 _cleanup_free_ char *e = NULL;
219 Manager *m = userdata;
220 unsigned long lu;
221 const char *p;
222 User *user;
223 int r;
224
225 assert(bus);
226 assert(path);
227 assert(interface);
228 assert(found);
229 assert(m);
230
231 p = startswith(path, "/org/freedesktop/login1/user/_");
232 if (!p)
233 return 0;
234
235 r = safe_atolu(p, &lu);
236 if (r < 0)
237 return 0;
238
239 user = hashmap_get(m->users, ULONG_TO_PTR(lu));
240 if (!user)
241 return 0;
242
243 *found = user;
244 return 1;
245 }
246
247 char *user_bus_path(User *u) {
248 char *s;
249
250 assert(u);
251
252 if (asprintf(&s, "/org/freedesktop/login1/user/_%llu", (unsigned long long) u->uid) < 0)
253 return NULL;
254
255 return s;
256 }
257
258 int user_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
259 _cleanup_strv_free_ char **l = NULL;
260 Manager *m = userdata;
261 User *user;
262 Iterator i;
263 int r;
264
265 assert(bus);
266 assert(path);
267 assert(nodes);
268
269 HASHMAP_FOREACH(user, m->users, i) {
270 char *p;
271
272 p = user_bus_path(user);
273 if (!p)
274 return -ENOMEM;
275
276 r = strv_push(&l, p);
277 if (r < 0) {
278 free(p);
279 return r;
280 }
281 }
282
283 *nodes = l;
284 l = NULL;
285
286 return 1;
287 }
288
289 int user_send_signal(User *u, bool new_user) {
290 _cleanup_free_ char *p = NULL;
291
292 assert(u);
293
294 p = user_bus_path(u);
295 if (!p)
296 return -ENOMEM;
297
298 return sd_bus_emit_signal(
299 u->manager->bus,
300 "/org/freedesktop/login1",
301 "org.freedesktop.login1.Manager",
302 new_user ? "UserNew" : "UserRemoved",
303 "uo", (uint32_t) u->uid, p);
304 }
305
306 int user_send_changed(User *u, const char *properties, ...) {
307 _cleanup_free_ char *p = NULL;
308 char **l;
309
310 assert(u);
311
312 if (!u->started)
313 return 0;
314
315 p = user_bus_path(u);
316 if (!p)
317 return -ENOMEM;
318
319 l = strv_from_stdarg_alloca(properties);
320
321 return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l);
322 }