]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-internal.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-internal.c
CommitLineData
de1c301e
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"
07630cea
LP
23#include "bus-message.h"
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') ||
151 *q == '_' || *q == '-';
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}