]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-convenience.c
bus: add new sd_bus_creds object to encapsulate process credentials
[thirdparty/systemd.git] / src / libsystemd-bus / bus-convenience.c
CommitLineData
992c052c
LP
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 "bus-internal.h"
23#include "bus-message.h"
24#include "bus-signature.h"
40ca29a1 25#include "bus-util.h"
e5609878 26#include "bus-type.h"
992c052c 27
d9f644e2 28_public_ int sd_bus_emit_signal(
992c052c
LP
29 sd_bus *bus,
30 const char *path,
31 const char *interface,
32 const char *member,
33 const char *types, ...) {
34
35 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
36 int r;
37
f69dc9a3
LP
38 assert_return(bus, -EINVAL);
39 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
40 assert_return(!bus_pid_changed(bus), -ECHILD);
992c052c
LP
41
42 r = sd_bus_message_new_signal(bus, path, interface, member, &m);
43 if (r < 0)
44 return r;
45
46 if (!isempty(types)) {
47 va_list ap;
48
49 va_start(ap, types);
50 r = bus_message_append_ap(m, types, ap);
51 va_end(ap);
52 if (r < 0)
53 return r;
54 }
55
56 return sd_bus_send(bus, m, NULL);
57}
58
d9f644e2 59_public_ int sd_bus_call_method(
992c052c
LP
60 sd_bus *bus,
61 const char *destination,
62 const char *path,
63 const char *interface,
64 const char *member,
65 sd_bus_error *error,
66 sd_bus_message **reply,
67 const char *types, ...) {
68
69 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
70 int r;
71
f69dc9a3
LP
72 assert_return(bus, -EINVAL);
73 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
74 assert_return(!bus_pid_changed(bus), -ECHILD);
992c052c
LP
75
76 r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
77 if (r < 0)
78 return r;
79
80 if (!isempty(types)) {
81 va_list ap;
82
83 va_start(ap, types);
84 r = bus_message_append_ap(m, types, ap);
85 va_end(ap);
86 if (r < 0)
87 return r;
88 }
89
c49b30a2 90 return sd_bus_call(bus, m, 0, error, reply);
992c052c
LP
91}
92
d9f644e2 93_public_ int sd_bus_reply_method_return(
992c052c
LP
94 sd_bus_message *call,
95 const char *types, ...) {
96
97 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
98 int r;
99
f69dc9a3
LP
100 assert_return(call, -EINVAL);
101 assert_return(call->sealed, -EPERM);
40ca29a1 102 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
df2d202e
LP
103 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
104 assert_return(!bus_pid_changed(call->bus), -ECHILD);
992c052c
LP
105
106 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
107 return 0;
108
df2d202e 109 r = sd_bus_message_new_method_return(call, &m);
992c052c
LP
110 if (r < 0)
111 return r;
112
113 if (!isempty(types)) {
114 va_list ap;
115
116 va_start(ap, types);
117 r = bus_message_append_ap(m, types, ap);
118 va_end(ap);
119 if (r < 0)
120 return r;
121 }
122
df2d202e 123 return sd_bus_send(call->bus, m, NULL);
992c052c
LP
124}
125
d9f644e2 126_public_ int sd_bus_reply_method_error(
992c052c
LP
127 sd_bus_message *call,
128 const sd_bus_error *e) {
129
130 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
131 int r;
132
f69dc9a3
LP
133 assert_return(call, -EINVAL);
134 assert_return(call->sealed, -EPERM);
40ca29a1 135 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
f69dc9a3 136 assert_return(sd_bus_error_is_set(e), -EINVAL);
df2d202e
LP
137 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
138 assert_return(!bus_pid_changed(call->bus), -ECHILD);
992c052c
LP
139
140 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
141 return 0;
142
df2d202e 143 r = sd_bus_message_new_method_error(call, e, &m);
992c052c
LP
144 if (r < 0)
145 return r;
146
df2d202e 147 return sd_bus_send(call->bus, m, NULL);
992c052c
LP
148}
149
d9f644e2 150_public_ int sd_bus_reply_method_errorf(
992c052c
LP
151 sd_bus_message *call,
152 const char *name,
153 const char *format,
154 ...) {
155
156 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
157 va_list ap;
992c052c 158
f69dc9a3
LP
159 assert_return(call, -EINVAL);
160 assert_return(call->sealed, -EPERM);
40ca29a1 161 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
df2d202e
LP
162 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
163 assert_return(!bus_pid_changed(call->bus), -ECHILD);
f69dc9a3
LP
164
165 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
166 return 0;
167
40ca29a1 168 va_start(ap, format);
780896a4 169 bus_error_setfv(&error, name, format, ap);
40ca29a1 170 va_end(ap);
992c052c 171
df2d202e 172 return sd_bus_reply_method_error(call, &error);
40ca29a1 173}
992c052c 174
d9f644e2 175_public_ int sd_bus_reply_method_errno(
40ca29a1
LP
176 sd_bus_message *call,
177 int error,
178 const sd_bus_error *p) {
992c052c 179
40ca29a1
LP
180 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
181
40ca29a1
LP
182 assert_return(call, -EINVAL);
183 assert_return(call->sealed, -EPERM);
184 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
df2d202e
LP
185 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
186 assert_return(!bus_pid_changed(call->bus), -ECHILD);
40ca29a1
LP
187
188 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
189 return 0;
190
191 if (sd_bus_error_is_set(p))
df2d202e 192 return sd_bus_reply_method_error(call, p);
40ca29a1
LP
193
194 sd_bus_error_set_errno(&berror, error);
195
df2d202e 196 return sd_bus_reply_method_error(call, &berror);
40ca29a1
LP
197}
198
d9f644e2 199_public_ int sd_bus_reply_method_errnof(
40ca29a1
LP
200 sd_bus_message *call,
201 int error,
202 const char *format,
203 ...) {
204
205 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
206 va_list ap;
207
40ca29a1
LP
208 assert_return(call, -EINVAL);
209 assert_return(call->sealed, -EPERM);
210 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
df2d202e
LP
211 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
212 assert_return(!bus_pid_changed(call->bus), -ECHILD);
40ca29a1
LP
213
214 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
215 return 0;
216
217 va_start(ap, format);
218 bus_error_set_errnofv(&berror, error, format, ap);
219 va_end(ap);
220
df2d202e 221 return sd_bus_reply_method_error(call, &berror);
992c052c
LP
222}
223
d9f644e2 224_public_ int sd_bus_get_property(
992c052c
LP
225 sd_bus *bus,
226 const char *destination,
227 const char *path,
228 const char *interface,
229 const char *member,
230 sd_bus_error *error,
231 sd_bus_message **reply,
232 const char *type) {
233
234 sd_bus_message *rep = NULL;
235 int r;
236
f69dc9a3
LP
237 assert_return(bus, -EINVAL);
238 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
239 assert_return(member_name_is_valid(member), -EINVAL);
240 assert_return(reply, -EINVAL);
241 assert_return(signature_is_single(type, false), -EINVAL);
242 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
243 assert_return(!bus_pid_changed(bus), -ECHILD);
992c052c
LP
244
245 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
246 if (r < 0)
247 return r;
248
249 r = sd_bus_message_enter_container(rep, 'v', type);
250 if (r < 0) {
251 sd_bus_message_unref(rep);
252 return r;
253 }
254
255 *reply = rep;
256 return 0;
257}
258
d9f644e2 259_public_ int sd_bus_get_property_trivial(
e5609878
LP
260 sd_bus *bus,
261 const char *destination,
262 const char *path,
263 const char *interface,
264 const char *member,
265 sd_bus_error *error,
266 char type, void *ptr) {
267
268 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
269 int r;
270
271 assert_return(bus, -EINVAL);
272 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
273 assert_return(member_name_is_valid(member), -EINVAL);
274 assert_return(bus_type_is_trivial(type), -EINVAL);
275 assert_return(ptr, -EINVAL);
276 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
277 assert_return(!bus_pid_changed(bus), -ECHILD);
278
279 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
280 if (r < 0)
281 return r;
282
283 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
284 if (r < 0)
285 return r;
286
287 r = sd_bus_message_read_basic(reply, type, ptr);
288 if (r < 0)
289 return r;
290
291 return 0;
292}
293
63be1989
LP
294_public_ int sd_bus_get_property_string(
295 sd_bus *bus,
296 const char *destination,
297 const char *path,
298 const char *interface,
299 const char *member,
300 sd_bus_error *error,
301 char **ret) {
302
303 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
304 const char *s;
305 char *n;
306 int r;
307
308 assert_return(bus, -EINVAL);
309 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
310 assert_return(member_name_is_valid(member), -EINVAL);
311 assert_return(ret, -EINVAL);
312 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
313 assert_return(!bus_pid_changed(bus), -ECHILD);
314
315 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
316 if (r < 0)
317 return r;
318
319 r = sd_bus_message_enter_container(reply, 'v', "s");
320 if (r < 0)
321 return r;
322
323 r = sd_bus_message_read_basic(reply, 's', &s);
324 if (r < 0)
325 return r;
326
327 n = strdup(s);
328 if (!n)
329 return -ENOMEM;
330
331 *ret = n;
332 return 0;
333}
334
335_public_ int sd_bus_get_property_strv(
336 sd_bus *bus,
337 const char *destination,
338 const char *path,
339 const char *interface,
340 const char *member,
341 sd_bus_error *error,
342 char ***ret) {
343
344 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
345 int r;
346
347 assert_return(bus, -EINVAL);
348 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
349 assert_return(member_name_is_valid(member), -EINVAL);
350 assert_return(ret, -EINVAL);
351 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
352 assert_return(!bus_pid_changed(bus), -ECHILD);
353
354 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
355 if (r < 0)
356 return r;
357
358 r = sd_bus_message_enter_container(reply, 'v', NULL);
359 if (r < 0)
360 return r;
361
362 r = sd_bus_message_read_strv(reply, ret);
363 if (r < 0)
364 return r;
365
366 return 0;
367}
368
d9f644e2 369_public_ int sd_bus_set_property(
992c052c
LP
370 sd_bus *bus,
371 const char *destination,
372 const char *path,
373 const char *interface,
374 const char *member,
375 sd_bus_error *error,
376 const char *type, ...) {
377
378 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
379 va_list ap;
380 int r;
381
f69dc9a3
LP
382 assert_return(bus, -EINVAL);
383 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
384 assert_return(member_name_is_valid(member), -EINVAL);
385 assert_return(signature_is_single(type, false), -EINVAL);
386 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
387 assert_return(!bus_pid_changed(bus), -ECHILD);
992c052c
LP
388
389 r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
390 if (r < 0)
391 return r;
392
393 r = sd_bus_message_append(m, "ss", strempty(interface), member);
394 if (r < 0)
395 return r;
396
397 r = sd_bus_message_open_container(m, 'v', type);
398 if (r < 0)
399 return r;
400
401 va_start(ap, type);
402 r = bus_message_append_ap(m, type, ap);
403 va_end(ap);
404 if (r < 0)
405 return r;
406
407 r = sd_bus_message_close_container(m);
408 if (r < 0)
409 return r;
410
c49b30a2 411 return sd_bus_call(bus, m, 0, error, NULL);
992c052c 412}
5b12334d
LP
413
414_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
415 sd_bus_creds *c;
416
417 assert_return(call, -EINVAL);
418 assert_return(call->sealed, -EPERM);
419 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
420 assert_return(!bus_pid_changed(call->bus), -ECHILD);
421
422 c = sd_bus_message_get_creds(call);
423
424 /* All data we need? */
425 if (c && (mask & ~c->mask) == 0) {
426 *creds = sd_bus_creds_ref(c);
427 return 0;
428 }
429
430 /* No data passed? Or not enough data passed to retrieve the missing bits? */
431 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
432 /* We couldn't read anything from the call, let's try
433 * to get it from the sender or peer */
434
435 if (call->sender)
436 return sd_bus_get_owner_creds(call->bus, call->sender, mask, creds);
437 else
438 return sd_bus_get_peer_creds(call->bus, mask, creds);
439 }
440
441 return sd_bus_creds_extend(c, mask, creds);
442}