chiark / gitweb /
sd-bus: make sure %m resolves to the specified error in bus_error_set_errnofv()
[elogind.git] / src / libsystemd / sd-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 char* service_name_startswith(const char *a, const char *b) {
170         const char *p;
171
172         if (!service_name_is_valid(a) ||
173             !service_name_is_valid(b))
174                 return NULL;
175
176         p = startswith(a, b);
177         if (!p)
178                 return NULL;
179
180         if (*p == 0)
181                 return (char*) p;
182
183         if (*p == '.')
184                 return (char*) p + 1;
185
186         return NULL;
187 }
188
189 bool member_name_is_valid(const char *p) {
190         const char *q;
191
192         if (isempty(p))
193                 return false;
194
195         for (q = p; *q; q++) {
196                 bool good;
197
198                 good =
199                         (*q >= 'a' && *q <= 'z') ||
200                         (*q >= 'A' && *q <= 'Z') ||
201                         (*q >= '0' && *q <= '9') ||
202                         *q == '_';
203
204                 if (!good)
205                         return false;
206         }
207
208         if (q - p > 255)
209                 return false;
210
211         return true;
212 }
213
214 static bool complex_pattern_check(char c, const char *a, const char *b) {
215         bool separator = false;
216
217         if (!a && !b)
218                 return true;
219
220         if (!a || !b)
221                 return false;
222
223         for (;;) {
224                 if (*a != *b)
225                         return (separator && (*a == 0 || *b == 0)) ||
226                                 (*a == 0 && *b == c && b[1] == 0) ||
227                                 (*b == 0 && *a == c && a[1] == 0);
228
229                 if (*a == 0)
230                         return true;
231
232                 separator = *a == c;
233
234                 a++, b++;
235         }
236 }
237
238 bool namespace_complex_pattern(const char *pattern, const char *value) {
239         return complex_pattern_check('.', pattern, value);
240 }
241
242 bool path_complex_pattern(const char *pattern, const char *value) {
243         return complex_pattern_check('/', pattern, value);
244 }
245
246 static bool simple_pattern_check(char c, const char *a, const char *b) {
247
248         if (!a && !b)
249                 return true;
250
251         if (!a || !b)
252                 return false;
253
254         for (;;) {
255                 if (*a != *b)
256                         return *a == 0 && *b == c;
257
258                 if (*a == 0)
259                         return true;
260
261                 a++, b++;
262         }
263 }
264
265 bool namespace_simple_pattern(const char *pattern, const char *value) {
266         return simple_pattern_check('.', pattern, value);
267 }
268
269 bool path_simple_pattern(const char *pattern, const char *value) {
270         return simple_pattern_check('/', pattern, value);
271 }
272
273 int bus_message_type_from_string(const char *s, uint8_t *u) {
274         if (streq(s, "signal"))
275                 *u = SD_BUS_MESSAGE_SIGNAL;
276         else if (streq(s, "method_call"))
277                 *u = SD_BUS_MESSAGE_METHOD_CALL;
278         else if (streq(s, "error"))
279                 *u = SD_BUS_MESSAGE_METHOD_ERROR;
280         else if (streq(s, "method_return"))
281                 *u = SD_BUS_MESSAGE_METHOD_RETURN;
282         else
283                 return -EINVAL;
284
285         return 0;
286 }
287
288 const char *bus_message_type_to_string(uint8_t u) {
289         if (u == SD_BUS_MESSAGE_SIGNAL)
290                 return "signal";
291         else if (u == SD_BUS_MESSAGE_METHOD_CALL)
292                 return "method_call";
293         else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
294                 return "error";
295         else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
296                  return "method_return";
297         else
298                 return NULL;
299 }
300
301 char *bus_address_escape(const char *v) {
302         const char *a;
303         char *r, *b;
304
305         r = new(char, strlen(v)*3+1);
306         if (!r)
307                 return NULL;
308
309         for (a = v, b = r; *a; a++) {
310
311                 if ((*a >= '0' && *a <= '9') ||
312                     (*a >= 'a' && *a <= 'z') ||
313                     (*a >= 'A' && *a <= 'Z') ||
314                     strchr("_-/.", *a))
315                         *(b++) = *a;
316                 else {
317                         *(b++) = '%';
318                         *(b++) = hexchar(*a >> 4);
319                         *(b++) = hexchar(*a & 0xF);
320                 }
321         }
322
323         *b = 0;
324         return r;
325 }