chiark / gitweb /
bus-proxy: whenever we cannot forward a message, report this back to caller, but...
[elogind.git] / src / bus-proxyd / synthesize.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2013 Daniel Mack
8   Copyright 2014 Kay Sievers
9
10   systemd is free software; you can redistribute it and/or modify it
11   under the terms of the GNU Lesser General Public License as published by
12   the Free Software Foundation; either version 2.1 of the License, or
13   (at your option) any later version.
14
15   systemd is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public License
21   along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stddef.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "sd-bus.h"
33 #include "bus-internal.h"
34 #include "bus-message.h"
35 #include "bus-util.h"
36 #include "strv.h"
37 #include "def.h"
38 #include "bus-control.h"
39 #include "synthesize.h"
40
41 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
42         int r;
43
44         assert(b);
45         assert(m);
46
47         r = bus_message_append_sender(m, "org.freedesktop.DBus");
48         if (r < 0)
49                 return r;
50
51         r = bus_seal_synthetic_message(b, m);
52         if (r < 0)
53                 return r;
54
55         return sd_bus_send(b, m, NULL);
56 }
57
58 int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
59         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
60         int r;
61
62         assert(call);
63
64         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
65                 return 0;
66
67         r = sd_bus_message_new_method_error(call, &m, e);
68         if (r < 0)
69                 return r;
70
71         return synthetic_driver_send(call->bus, m);
72 }
73
74 int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) {
75         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
76         va_list ap;
77
78         va_start(ap, format);
79         bus_error_setfv(&error, name, format, ap);
80         va_end(ap);
81
82         return synthetic_reply_method_error(call, &error);
83 }
84
85 int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
86         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
87
88         assert(call);
89
90         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
91                 return 0;
92
93         if (sd_bus_error_is_set(p))
94                 return synthetic_reply_method_error(call, p);
95
96         sd_bus_error_set_errno(&berror, error);
97
98         return synthetic_reply_method_error(call, &berror);
99 }
100
101 int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) {
102         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
103         va_list ap;
104
105         assert(call);
106
107         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
108                 return 0;
109
110         va_start(ap, format);
111         sd_bus_error_set_errnofv(&berror, error, format, ap);
112         va_end(ap);
113
114         return synthetic_reply_method_error(call, &berror);
115 }
116
117 int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
118         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
119         int r;
120
121         assert(call);
122
123         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
124                 return 0;
125
126         r = sd_bus_message_new_method_return(call, &m);
127         if (r < 0)
128                 return r;
129
130         if (!isempty(types)) {
131                 va_list ap;
132
133                 va_start(ap, types);
134                 r = bus_message_append_ap(m, types, ap);
135                 va_end(ap);
136                 if (r < 0)
137                         return r;
138         }
139
140         return synthetic_driver_send(call->bus, m);
141 }
142
143 int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) {
144         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
145         int r;
146
147         assert(call);
148
149         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
150                 return 0;
151
152         r = sd_bus_message_new_method_return(call, &m);
153         if (r < 0)
154                 return synthetic_reply_method_errno(call, r, NULL);
155
156         r = sd_bus_message_append_strv(m, l);
157         if (r < 0)
158                 return synthetic_reply_method_errno(call, r, NULL);
159
160         return synthetic_driver_send(call->bus, m);
161 }
162
163 int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
164         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
165         const char *name, *old_owner, *new_owner;
166         int r;
167
168         assert(a);
169         assert(b);
170         assert(m);
171
172         /* If we get NameOwnerChanged for our own name, we need to
173          * synthesize NameLost/NameAcquired, since socket clients need
174          * that, even though it is obsoleted on kdbus */
175
176         if (!a->is_kernel)
177                 return 0;
178
179         if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
180             !streq_ptr(m->path, "/org/freedesktop/DBus") ||
181             !streq_ptr(m->sender, "org.freedesktop.DBus"))
182                 return 0;
183
184         r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
185         if (r < 0)
186                 return r;
187
188         r = sd_bus_message_rewind(m, true);
189         if (r < 0)
190                 return r;
191
192         if (streq(old_owner, a->unique_name)) {
193
194                 r = sd_bus_message_new_signal(
195                                 b,
196                                 &n,
197                                 "/org/freedesktop/DBus",
198                                 "org.freedesktop.DBus",
199                                 "NameLost");
200
201         } else if (streq(new_owner, a->unique_name)) {
202
203                 r = sd_bus_message_new_signal(
204                                 b,
205                                 &n,
206                                 "/org/freedesktop/DBus",
207                                 "org.freedesktop.DBus",
208                                 "NameAcquired");
209         } else
210                 return 0;
211
212         if (r < 0)
213                 return r;
214
215         r = sd_bus_message_append(n, "s", name);
216         if (r < 0)
217                 return r;
218
219         r = bus_message_append_sender(n, "org.freedesktop.DBus");
220         if (r < 0)
221                 return r;
222
223         r = bus_seal_synthetic_message(b, n);
224         if (r < 0)
225                 return r;
226
227         return sd_bus_send(b, n, NULL);
228 }