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