chiark / gitweb /
fsckd: the error code is actually returned in 'fd'
[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 <stddef.h>
25
26 #include "util.h"
27 #include "sd-bus.h"
28 #include "bus-internal.h"
29 #include "bus-message.h"
30 #include "bus-util.h"
31 #include "synthesize.h"
32
33 static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
34         int r;
35
36         assert(b);
37         assert(m);
38
39         r = bus_message_append_sender(m, "org.freedesktop.DBus");
40         if (r < 0)
41                 return r;
42
43         r = bus_seal_synthetic_message(b, m);
44         if (r < 0)
45                 return r;
46
47         return sd_bus_send(b, m, NULL);
48 }
49
50 int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
51         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
52         int r;
53
54         assert(call);
55
56         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
57                 return 0;
58
59         r = sd_bus_message_new_method_error(call, &m, e);
60         if (r < 0)
61                 return r;
62
63         return synthetic_driver_send(call->bus, m);
64 }
65
66 int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) {
67         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68         va_list ap;
69
70         va_start(ap, format);
71         bus_error_setfv(&error, name, format, ap);
72         va_end(ap);
73
74         return synthetic_reply_method_error(call, &error);
75 }
76
77 int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
78         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
79
80         assert(call);
81
82         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
83                 return 0;
84
85         if (sd_bus_error_is_set(p))
86                 return synthetic_reply_method_error(call, p);
87
88         sd_bus_error_set_errno(&berror, error);
89
90         return synthetic_reply_method_error(call, &berror);
91 }
92
93 int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) {
94         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
95         va_list ap;
96
97         assert(call);
98
99         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
100                 return 0;
101
102         va_start(ap, format);
103         sd_bus_error_set_errnofv(&berror, error, format, ap);
104         va_end(ap);
105
106         return synthetic_reply_method_error(call, &berror);
107 }
108
109 int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
110         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
111         int r;
112
113         assert(call);
114
115         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
116                 return 0;
117
118         r = sd_bus_message_new_method_return(call, &m);
119         if (r < 0)
120                 return r;
121
122         if (!isempty(types)) {
123                 va_list ap;
124
125                 va_start(ap, types);
126                 r = bus_message_append_ap(m, types, ap);
127                 va_end(ap);
128                 if (r < 0)
129                         return r;
130         }
131
132         return synthetic_driver_send(call->bus, m);
133 }
134
135 int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) {
136         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
137         int r;
138
139         assert(call);
140
141         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
142                 return 0;
143
144         r = sd_bus_message_new_method_return(call, &m);
145         if (r < 0)
146                 return synthetic_reply_method_errno(call, r, NULL);
147
148         r = sd_bus_message_append_strv(m, l);
149         if (r < 0)
150                 return synthetic_reply_method_errno(call, r, NULL);
151
152         return synthetic_driver_send(call->bus, m);
153 }
154
155 int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
156         _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
157         const char *name, *old_owner, *new_owner;
158         int r;
159
160         assert(a);
161         assert(b);
162         assert(m);
163
164         /* If we get NameOwnerChanged for our own name, we need to
165          * synthesize NameLost/NameAcquired, since socket clients need
166          * that, even though it is obsoleted on kdbus */
167
168         if (!a->is_kernel)
169                 return 0;
170
171         if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
172             !streq_ptr(m->path, "/org/freedesktop/DBus") ||
173             !streq_ptr(m->sender, "org.freedesktop.DBus"))
174                 return 0;
175
176         r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
177         if (r < 0)
178                 return r;
179
180         r = sd_bus_message_rewind(m, true);
181         if (r < 0)
182                 return r;
183
184         if (streq(old_owner, a->unique_name)) {
185
186                 r = sd_bus_message_new_signal(
187                                 b,
188                                 &n,
189                                 "/org/freedesktop/DBus",
190                                 "org.freedesktop.DBus",
191                                 "NameLost");
192
193         } else if (streq(new_owner, a->unique_name)) {
194
195                 r = sd_bus_message_new_signal(
196                                 b,
197                                 &n,
198                                 "/org/freedesktop/DBus",
199                                 "org.freedesktop.DBus",
200                                 "NameAcquired");
201         } else
202                 return 0;
203
204         if (r < 0)
205                 return r;
206
207         r = sd_bus_message_append(n, "s", name);
208         if (r < 0)
209                 return r;
210
211         r = bus_message_append_sender(n, "org.freedesktop.DBus");
212         if (r < 0)
213                 return r;
214
215         r = bus_seal_synthetic_message(b, n);
216         if (r < 0)
217                 return r;
218
219         return sd_bus_send(b, n, NULL);
220 }