chiark / gitweb /
bus: we really need to get rid of the :no-sender hack
[elogind.git] / src / libsystemd-bus / bus-internal.c
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
24 bool object_path_is_valid(const char *p) {
25         const char *q;
26         bool slash;
27
28         if (!p)
29                 return false;
30
31         if (p[0] != '/')
32                 return false;
33
34         if (p[1] == 0)
35                 return true;
36
37         for (slash = true, q = p+1; *q; q++)
38                 if (*q == '/') {
39                         if (slash)
40                                 return false;
41
42                         slash = true;
43                 } else {
44                         bool good;
45
46                         good =
47                                 (*q >= 'a' && *q <= 'z') ||
48                                 (*q >= 'A' && *q <= 'Z') ||
49                                 (*q >= '0' && *q <= '9') ||
50                                 *q == '_';
51
52                         if (!good)
53                                 return false;
54
55                         slash = false;
56                 }
57
58         if (slash)
59                 return false;
60
61         return true;
62 }
63
64 char* object_path_startswith(const char *a, const char *b) {
65         const char *p;
66
67         if (!object_path_is_valid(a) ||
68             !object_path_is_valid(b))
69                 return NULL;
70
71         if (streq(b, "/"))
72                 return (char*) a + 1;
73
74         p = startswith(a, b);
75         if (!p)
76                 return NULL;
77
78         if (*p == 0)
79                 return (char*) p;
80
81         if (*p == '/')
82                 return (char*) p + 1;
83
84         return NULL;
85 }
86
87 bool interface_name_is_valid(const char *p) {
88         const char *q;
89         bool dot, found_dot = false;
90
91         if (isempty(p))
92                 return false;
93
94         for (dot = true, q = p; *q; q++)
95                 if (*q == '.') {
96                         if (dot)
97                                 return false;
98
99                         found_dot = dot = true;
100                 } else {
101                         bool good;
102
103                         good =
104                                 (*q >= 'a' && *q <= 'z') ||
105                                 (*q >= 'A' && *q <= 'Z') ||
106                                 (!dot && *q >= '0' && *q <= '9') ||
107                                 *q == '_';
108
109                         if (!good)
110                                 return false;
111
112                         dot = false;
113                 }
114
115         if (q - p > 255)
116                 return false;
117
118         if (dot)
119                 return false;
120
121         if (!found_dot)
122                 return false;
123
124         return true;
125 }
126
127 bool service_name_is_valid(const char *p) {
128         const char *q;
129         bool dot, found_dot = false, unique;
130
131         if (isempty(p))
132                 return false;
133
134         unique = p[0] == ':';
135
136         for (dot = true, q = unique ? p+1 : p; *q; q++)
137                 if (*q == '.') {
138                         if (dot)
139                                 return false;
140
141                         found_dot = dot = true;
142                 } else {
143                         bool good;
144
145                         good =
146                                 (*q >= 'a' && *q <= 'z') ||
147                                 (*q >= 'A' && *q <= 'Z') ||
148                                 ((!dot || unique) && *q >= '0' && *q <= '9') ||
149                                 *q == '_' || *q == '-';
150
151                         if (!good)
152                                 return false;
153
154                         dot = false;
155                 }
156
157         if (q - p > 255)
158                 return false;
159
160         if (dot)
161                 return false;
162
163         if (!found_dot)
164                 return false;
165
166         return true;
167 }
168
169 bool sender_name_is_valid(const char *p) {
170         if (isempty(p))
171                 return false;
172
173         /* FIXME: remove after PID 1 bus conversion */
174         if (streq(p, ":no-sender"))
175                 return true;
176
177         return service_name_is_valid(p);
178 }
179
180 bool member_name_is_valid(const char *p) {
181         const char *q;
182
183         if (isempty(p))
184                 return false;
185
186         for (q = p; *q; q++) {
187                 bool good;
188
189                 good =
190                         (*q >= 'a' && *q <= 'z') ||
191                         (*q >= 'A' && *q <= 'Z') ||
192                         (*q >= '0' && *q <= '9') ||
193                         *q == '_';
194
195                 if (!good)
196                         return false;
197         }
198
199         if (q - p > 255)
200                 return false;
201
202         return true;
203 }
204
205 static bool complex_pattern_check(char c, const char *a, const char *b) {
206         bool separator = false;
207
208         if (!a && !b)
209                 return true;
210
211         if (!a || !b)
212                 return false;
213
214         for (;;) {
215                 if (*a != *b)
216                         return (separator && (*a == 0 || *b == 0)) ||
217                                 (*a == 0 && *b == c && b[1] == 0) ||
218                                 (*b == 0 && *a == c && a[1] == 0);
219
220                 if (*a == 0)
221                         return true;
222
223                 separator = *a == c;
224
225                 a++, b++;
226         }
227 }
228
229 bool namespace_complex_pattern(const char *pattern, const char *value) {
230         return complex_pattern_check('.', pattern, value);
231 }
232
233 bool path_complex_pattern(const char *pattern, const char *value) {
234         return complex_pattern_check('/', pattern, value);
235 }
236
237 static bool simple_pattern_check(char c, const char *a, const char *b) {
238
239         if (!a && !b)
240                 return true;
241
242         if (!a || !b)
243                 return false;
244
245         for (;;) {
246                 if (*a != *b)
247                         return *a == 0 && *b == c;
248
249                 if (*a == 0)
250                         return true;
251
252                 a++, b++;
253         }
254 }
255
256 bool namespace_simple_pattern(const char *pattern, const char *value) {
257         return simple_pattern_check('.', pattern, value);
258 }
259
260 bool path_simple_pattern(const char *pattern, const char *value) {
261         return simple_pattern_check('/', pattern, value);
262 }
263
264 int bus_message_type_from_string(const char *s, uint8_t *u) {
265         if (streq(s, "signal"))
266                 *u = SD_BUS_MESSAGE_SIGNAL;
267         else if (streq(s, "method_call"))
268                 *u = SD_BUS_MESSAGE_METHOD_CALL;
269         else if (streq(s, "error"))
270                 *u = SD_BUS_MESSAGE_METHOD_ERROR;
271         else if (streq(s, "method_return"))
272                 *u = SD_BUS_MESSAGE_METHOD_RETURN;
273         else
274                 return -EINVAL;
275
276         return 0;
277 }
278
279 const char *bus_message_type_to_string(uint8_t u) {
280         if (u == SD_BUS_MESSAGE_SIGNAL)
281                 return "signal";
282         else if (u == SD_BUS_MESSAGE_METHOD_CALL)
283                 return "method_call";
284         else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
285                 return "error";
286         else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
287                  return "method_return";
288         else
289                 return NULL;
290 }
291
292 char *bus_address_escape(const char *v) {
293         const char *a;
294         char *r, *b;
295
296         r = new(char, strlen(v)*3+1);
297         if (!r)
298                 return NULL;
299
300         for (a = v, b = r; *a; a++) {
301
302                 if ((*a >= '0' && *a <= '9') ||
303                     (*a >= 'a' && *a <= 'z') ||
304                     (*a >= 'A' && *a <= 'Z') ||
305                     strchr("_-/.", *a))
306                         *(b++) = *a;
307                 else {
308                         *(b++) = '%';
309                         *(b++) = hexchar(*a >> 4);
310                         *(b++) = hexchar(*a & 0xF);
311                 }
312         }
313
314         *b = 0;
315         return r;
316 }