]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-internal.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-internal.c
CommitLineData
de1c301e
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2013 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
b5efdb8a 20#include "alloc-util.h"
de1c301e 21#include "bus-internal.h"
07630cea 22#include "bus-message.h"
e4e73a63 23#include "hexdecoct.h"
07630cea 24#include "string-util.h"
ac89bf1d
LP
25
26bool object_path_is_valid(const char *p) {
27 const char *q;
28 bool slash;
29
30 if (!p)
31 return false;
32
33 if (p[0] != '/')
34 return false;
35
36 if (p[1] == 0)
37 return true;
38
39 for (slash = true, q = p+1; *q; q++)
40 if (*q == '/') {
41 if (slash)
42 return false;
43
44 slash = true;
45 } else {
46 bool good;
47
48 good =
49 (*q >= 'a' && *q <= 'z') ||
50 (*q >= 'A' && *q <= 'Z') ||
51 (*q >= '0' && *q <= '9') ||
52 *q == '_';
53
54 if (!good)
55 return false;
56
57 slash = false;
58 }
59
60 if (slash)
61 return false;
62
63 return true;
64}
6693860f 65
29ddb38f
LP
66char* object_path_startswith(const char *a, const char *b) {
67 const char *p;
68
69 if (!object_path_is_valid(a) ||
70 !object_path_is_valid(b))
71 return NULL;
72
73 if (streq(b, "/"))
74 return (char*) a + 1;
75
76 p = startswith(a, b);
77 if (!p)
78 return NULL;
79
80 if (*p == 0)
81 return (char*) p;
82
83 if (*p == '/')
84 return (char*) p + 1;
85
86 return NULL;
87}
88
6693860f
LP
89bool interface_name_is_valid(const char *p) {
90 const char *q;
f5f6e41a 91 bool dot, found_dot = false;
6693860f
LP
92
93 if (isempty(p))
94 return false;
95
96 for (dot = true, q = p; *q; q++)
97 if (*q == '.') {
98 if (dot)
99 return false;
100
101 found_dot = dot = true;
102 } else {
103 bool good;
104
105 good =
106 (*q >= 'a' && *q <= 'z') ||
107 (*q >= 'A' && *q <= 'Z') ||
108 (!dot && *q >= '0' && *q <= '9') ||
109 *q == '_';
110
111 if (!good)
112 return false;
113
114 dot = false;
115 }
116
117 if (q - p > 255)
118 return false;
119
120 if (dot)
121 return false;
122
123 if (!found_dot)
124 return false;
125
126 return true;
127}
128
129bool service_name_is_valid(const char *p) {
130 const char *q;
f5f6e41a 131 bool dot, found_dot = false, unique;
6693860f
LP
132
133 if (isempty(p))
134 return false;
135
136 unique = p[0] == ':';
137
138 for (dot = true, q = unique ? p+1 : p; *q; q++)
139 if (*q == '.') {
140 if (dot)
141 return false;
142
143 found_dot = dot = true;
144 } else {
145 bool good;
146
147 good =
148 (*q >= 'a' && *q <= 'z') ||
149 (*q >= 'A' && *q <= 'Z') ||
150 ((!dot || unique) && *q >= '0' && *q <= '9') ||
945c2931 151 IN_SET(*q, '_', '-');
6693860f
LP
152
153 if (!good)
154 return false;
155
156 dot = false;
157 }
158
159 if (q - p > 255)
160 return false;
161
162 if (dot)
163 return false;
164
165 if (!found_dot)
166 return false;
167
168 return true;
6693860f
LP
169}
170
f5d8989c
LP
171char* service_name_startswith(const char *a, const char *b) {
172 const char *p;
173
174 if (!service_name_is_valid(a) ||
175 !service_name_is_valid(b))
176 return NULL;
177
178 p = startswith(a, b);
179 if (!p)
180 return NULL;
181
182 if (*p == 0)
183 return (char*) p;
184
185 if (*p == '.')
186 return (char*) p + 1;
187
188 return NULL;
189}
190
6693860f
LP
191bool member_name_is_valid(const char *p) {
192 const char *q;
193
194 if (isempty(p))
195 return false;
196
197 for (q = p; *q; q++) {
198 bool good;
199
200 good =
201 (*q >= 'a' && *q <= 'z') ||
202 (*q >= 'A' && *q <= 'Z') ||
203 (*q >= '0' && *q <= '9') ||
204 *q == '_';
205
206 if (!good)
207 return false;
208 }
209
210 if (q - p > 255)
211 return false;
212
213 return true;
214}
392d5b37 215
744dccdd
DH
216/*
217 * Complex pattern match
218 * This checks whether @a is a 'complex-prefix' of @b, or @b is a
219 * 'complex-prefix' of @a, based on strings that consist of labels with @c as
220 * spearator. This function returns true if:
221 * - both strings are equal
222 * - either is a prefix of the other and ends with @c
223 * The second rule makes sure that either string needs to be fully included in
224 * the other, and the string which is considered the prefix needs to end with a
225 * separator.
226 */
392d5b37
LP
227static bool complex_pattern_check(char c, const char *a, const char *b) {
228 bool separator = false;
229
42c5aaf3
LP
230 if (!a && !b)
231 return true;
232
233 if (!a || !b)
234 return false;
235
392d5b37
LP
236 for (;;) {
237 if (*a != *b)
744dccdd 238 return (separator && (*a == 0 || *b == 0));
392d5b37
LP
239
240 if (*a == 0)
241 return true;
242
243 separator = *a == c;
244
245 a++, b++;
246 }
247}
248
249bool namespace_complex_pattern(const char *pattern, const char *value) {
250 return complex_pattern_check('.', pattern, value);
251}
252
253bool path_complex_pattern(const char *pattern, const char *value) {
254 return complex_pattern_check('/', pattern, value);
255}
256
744dccdd
DH
257/*
258 * Simple pattern match
259 * This checks whether @a is a 'simple-prefix' of @b, based on strings that
260 * consist of labels with @c as separator. This function returns true, if:
261 * - if @a and @b are equal
262 * - if @a is a prefix of @b, and the first following character in @b (or the
263 * last character in @a) is @c
264 * The second rule basically makes sure that if @a is a prefix of @b, then @b
265 * must follow with a new label separated by @c. It cannot extend the label.
266 */
392d5b37 267static bool simple_pattern_check(char c, const char *a, const char *b) {
744dccdd 268 bool separator = false;
42c5aaf3
LP
269
270 if (!a && !b)
271 return true;
272
273 if (!a || !b)
274 return false;
275
392d5b37
LP
276 for (;;) {
277 if (*a != *b)
744dccdd 278 return *a == 0 && (*b == c || separator);
392d5b37
LP
279
280 if (*a == 0)
281 return true;
282
744dccdd
DH
283 separator = *a == c;
284
392d5b37
LP
285 a++, b++;
286 }
287}
288
289bool namespace_simple_pattern(const char *pattern, const char *value) {
290 return simple_pattern_check('.', pattern, value);
291}
292
293bool path_simple_pattern(const char *pattern, const char *value) {
294 return simple_pattern_check('/', pattern, value);
295}
296
297int bus_message_type_from_string(const char *s, uint8_t *u) {
298 if (streq(s, "signal"))
40ca29a1 299 *u = SD_BUS_MESSAGE_SIGNAL;
392d5b37 300 else if (streq(s, "method_call"))
40ca29a1 301 *u = SD_BUS_MESSAGE_METHOD_CALL;
392d5b37 302 else if (streq(s, "error"))
40ca29a1 303 *u = SD_BUS_MESSAGE_METHOD_ERROR;
392d5b37 304 else if (streq(s, "method_return"))
40ca29a1 305 *u = SD_BUS_MESSAGE_METHOD_RETURN;
392d5b37
LP
306 else
307 return -EINVAL;
308
309 return 0;
310}
a56f19c4
LP
311
312const char *bus_message_type_to_string(uint8_t u) {
40ca29a1 313 if (u == SD_BUS_MESSAGE_SIGNAL)
a56f19c4 314 return "signal";
40ca29a1 315 else if (u == SD_BUS_MESSAGE_METHOD_CALL)
a56f19c4 316 return "method_call";
40ca29a1 317 else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
a56f19c4 318 return "error";
40ca29a1 319 else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
a56f19c4
LP
320 return "method_return";
321 else
322 return NULL;
323}
0f8bd8de
LP
324
325char *bus_address_escape(const char *v) {
326 const char *a;
327 char *r, *b;
328
329 r = new(char, strlen(v)*3+1);
330 if (!r)
331 return NULL;
332
333 for (a = v, b = r; *a; a++) {
334
335 if ((*a >= '0' && *a <= '9') ||
336 (*a >= 'a' && *a <= 'z') ||
337 (*a >= 'A' && *a <= 'Z') ||
338 strchr("_-/.", *a))
339 *(b++) = *a;
340 else {
341 *(b++) = '%';
342 *(b++) = hexchar(*a >> 4);
343 *(b++) = hexchar(*a & 0xF);
344 }
345 }
346
347 *b = 0;
348 return r;
349}
a095315b
KS
350
351int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
352 assert(m);
353
354 if (r < 0) {
355 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
356 sd_bus_reply_method_errno(m, r, error);
357
358 } else if (sd_bus_error_is_set(error)) {
359 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
360 sd_bus_reply_method_error(m, error);
361 } else
362 return r;
363
364 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
365 bus_message_type_to_string(m->header->type),
366 strna(m->sender),
367 strna(m->path),
368 strna(m->interface),
369 strna(m->member),
370 strna(m->root_container.signature),
371 bus_error_message(error, r));
372
373 return 1;
374}