chiark / gitweb /
fc71fcf22ec0103d15761b6d194835e0a1d78171
[elogind.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 }