chiark / gitweb /
177bd882ada36c569bfc68d31f65459bc775c61e
[elogind.git] / src / libsystemd-bus / bus-control.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 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <stddef.h>
27 #include <errno.h>
28
29 #include "strv.h"
30
31 #include "sd-bus.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-control.h"
35
36 int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
37         int r;
38
39         if (!bus)
40                 return -EINVAL;
41         if (!unique)
42                 return -EINVAL;
43         if (bus_pid_changed(bus))
44                 return -ECHILD;
45
46         r = bus_ensure_running(bus);
47         if (r < 0)
48                 return r;
49
50         *unique = bus->unique_name;
51         return 0;
52 }
53
54 int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
55         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
56         uint32_t ret;
57         int r;
58
59         if (!bus)
60                 return -EINVAL;
61         if (!name)
62                 return -EINVAL;
63         if (!bus->bus_client)
64                 return -EINVAL;
65         if (!BUS_IS_OPEN(bus->state))
66                 return -ENOTCONN;
67         if (bus_pid_changed(bus))
68                 return -ECHILD;
69
70         if (bus->is_kernel) {
71                 struct kdbus_cmd_name *n;
72                 size_t l;
73
74                 l = strlen(name);
75                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
76                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
77                 n->name_flags = flags;
78                 memcpy(n->name, name, l+1);
79
80 #ifdef HAVE_VALGRIND_MEMCHECK_H
81                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
82 #endif
83
84                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
85                 if (r < 0)
86                         return -errno;
87
88                 return n->name_flags;
89         } else {
90                 r = sd_bus_call_method(
91                                 bus,
92                                 "org.freedesktop.DBus",
93                                 "/",
94                                 "org.freedesktop.DBus",
95                                 "RequestName",
96                                 NULL,
97                                 &reply,
98                                 "su",
99                                 name,
100                                 flags);
101                 if (r < 0)
102                         return r;
103
104                 r = sd_bus_message_read(reply, "u", &ret);
105                 if (r < 0)
106                         return r;
107
108                 return ret;
109         }
110 }
111
112 int sd_bus_release_name(sd_bus *bus, const char *name) {
113         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
114         uint32_t ret;
115         int r;
116
117         if (!bus)
118                 return -EINVAL;
119         if (!name)
120                 return -EINVAL;
121         if (!bus->bus_client)
122                 return -EINVAL;
123         if (!BUS_IS_OPEN(bus->state))
124                 return -ENOTCONN;
125         if (bus_pid_changed(bus))
126                 return -ECHILD;
127
128         if (bus->is_kernel) {
129                 struct kdbus_cmd_name *n;
130                 size_t l;
131
132                 l = strlen(name);
133                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
134                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
135                 memcpy(n->name, name, l+1);
136
137 #ifdef HAVE_VALGRIND_MEMCHECK_H
138                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
139 #endif
140                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
141                 if (r < 0)
142                         return -errno;
143
144                 return n->name_flags;
145         } else {
146                 r = sd_bus_call_method(
147                                 bus,
148                                 "org.freedesktop.DBus",
149                                 "/",
150                                 "org.freedesktop.DBus",
151                                 "ReleaseName",
152                                 NULL,
153                                 &reply,
154                                 "s",
155                                 name);
156                 if (r < 0)
157                         return r;
158
159                 r = sd_bus_message_read(reply, "u", &ret);
160                 if (r < 0)
161                         return r;
162         }
163
164         return ret;
165 }
166
167 int sd_bus_list_names(sd_bus *bus, char ***l) {
168         _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
169         char **x = NULL;
170         int r;
171
172         if (!bus)
173                 return -EINVAL;
174         if (!l)
175                 return -EINVAL;
176         if (!BUS_IS_OPEN(bus->state))
177                 return -ENOTCONN;
178         if (bus_pid_changed(bus))
179                 return -ECHILD;
180
181         r = sd_bus_call_method(
182                         bus,
183                         "org.freedesktop.DBus",
184                         "/",
185                         "org.freedesktop.DBus",
186                         "ListNames",
187                         NULL,
188                         &reply1,
189                         NULL);
190         if (r < 0)
191                 return r;
192
193         r = sd_bus_call_method(
194                         bus,
195                         "org.freedesktop.DBus",
196                         "/",
197                         "org.freedesktop.DBus",
198                         "ListActivatableNames",
199                         NULL,
200                         &reply2,
201                         NULL);
202         if (r < 0)
203                 return r;
204
205         r = bus_message_read_strv_extend(reply1, &x);
206         if (r < 0) {
207                 strv_free(x);
208                 return r;
209         }
210
211         r = bus_message_read_strv_extend(reply2, &x);
212         if (r < 0) {
213                 strv_free(x);
214                 return r;
215         }
216
217         *l = strv_uniq(x);
218         return 0;
219 }
220
221 int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) {
222         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
223         const char *found;
224         int r;
225
226         if (!bus)
227                 return -EINVAL;
228         if (!name)
229                 return -EINVAL;
230         if (!BUS_IS_OPEN(bus->state))
231                 return -ENOTCONN;
232         if (bus_pid_changed(bus))
233                 return -ECHILD;
234
235         r = sd_bus_call_method(
236                         bus,
237                         "org.freedesktop.DBus",
238                         "/",
239                         "org.freedesktop.DBus",
240                         "GetNameOwner",
241                         NULL,
242                         &reply,
243                         "s",
244                         name);
245         if (r < 0)
246                 return r;
247
248         r = sd_bus_message_read(reply, "s", &found);
249         if (r < 0)
250                 return r;
251
252         if (owner) {
253                 char *t;
254
255                 t = strdup(found);
256                 if (!t)
257                         return -ENOMEM;
258
259                 *owner = t;
260         }
261
262         return 0;
263 }
264
265 int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) {
266         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
267         uint32_t u;
268         int r;
269
270         if (!bus)
271                 return -EINVAL;
272         if (!name)
273                 return -EINVAL;
274         if (!uid)
275                 return -EINVAL;
276         if (!BUS_IS_OPEN(bus->state))
277                 return -ENOTCONN;
278         if (bus_pid_changed(bus))
279                 return -ECHILD;
280
281         r = sd_bus_call_method(
282                         bus,
283                         "org.freedesktop.DBus",
284                         "/",
285                         "org.freedesktop.DBus",
286                         "GetConnectionUnixUser",
287                         NULL,
288                         &reply,
289                         "s",
290                         name);
291         if (r < 0)
292                 return r;
293
294         r = sd_bus_message_read(reply, "u", &u);
295         if (r < 0)
296                 return r;
297
298         *uid = (uid_t) u;
299         return 0;
300 }
301
302 int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
303         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
304         uint32_t u;
305         int r;
306
307         if (!bus)
308                 return -EINVAL;
309         if (!name)
310                 return -EINVAL;
311         if (!pid)
312                 return -EINVAL;
313         if (!BUS_IS_OPEN(bus->state))
314                 return -ENOTCONN;
315         if (bus_pid_changed(bus))
316                 return -ECHILD;
317
318         r = sd_bus_call_method(
319                         bus,
320                         "org.freedesktop.DBus",
321                         "/",
322                         "org.freedesktop.DBus",
323                         "GetConnectionUnixProcessID",
324                         NULL,
325                         &reply,
326                         "s",
327                         name);
328         if (r < 0)
329                 return r;
330
331         r = sd_bus_message_read(reply, "u", &u);
332         if (r < 0)
333                 return r;
334
335         if (u == 0)
336                 return -EIO;
337
338         *pid = (uid_t) u;
339         return 0;
340 }
341
342 int bus_add_match_internal(sd_bus *bus, const char *match) {
343         assert(bus);
344         assert(match);
345
346         return sd_bus_call_method(
347                         bus,
348                         "org.freedesktop.DBus",
349                         "/",
350                         "org.freedesktop.DBus",
351                         "AddMatch",
352                         NULL,
353                         NULL,
354                         "s",
355                         match);
356 }
357
358 int bus_remove_match_internal(sd_bus *bus, const char *match) {
359         assert(bus);
360         assert(match);
361
362         return sd_bus_call_method(
363                         bus,
364                         "org.freedesktop.DBus",
365                         "/",
366                         "org.freedesktop.DBus",
367                         "RemoveMatch",
368                         NULL,
369                         NULL,
370                         "s",
371                         match);
372 }
373
374 int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
375         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
376         const char *mid;
377         int r;
378
379         if (!bus)
380                 return -EINVAL;
381         if (!name)
382                 return -EINVAL;
383         if (!BUS_IS_OPEN(bus->state))
384                 return -ENOTCONN;
385         if (bus_pid_changed(bus))
386                 return -ECHILD;
387
388         if (streq_ptr(name, bus->unique_name))
389                 return sd_id128_get_machine(machine);
390
391         r = sd_bus_call_method(bus,
392                                name,
393                                "/",
394                                "org.freedesktop.DBus.Peer",
395                                "GetMachineId",
396                                NULL,
397                                &reply,
398                                NULL);
399
400         if (r < 0)
401                 return r;
402
403         r = sd_bus_message_read(reply, "s", &mid);
404         if (r < 0)
405                 return r;
406
407         return sd_id128_from_string(mid, machine);
408 }