chiark / gitweb /
always include config.h from Makefile
[elogind.git] / udev / lib / libudev-util.c
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <dirent.h>
27 #include <ctype.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30
31 #include "libudev.h"
32 #include "libudev-private.h"
33
34 static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *syspath, char *subsystem, size_t size)
35 {
36         char path[UTIL_PATH_SIZE];
37         ssize_t len;
38         const char *pos;
39
40         util_strlcpy(path, syspath, sizeof(path));
41         util_strlcat(path, "/", sizeof(path));
42         util_strlcat(path, slink, sizeof(path));
43         len = readlink(path, path, sizeof(path));
44         if (len < 0 || len >= (ssize_t) sizeof(path))
45                 return -1;
46         path[len] = '\0';
47         pos = strrchr(path, '/');
48         if (pos == NULL)
49                 return -1;
50         pos = &pos[1];
51         info(udev, "resolved link to: '%s'\n", pos);
52         return util_strlcpy(subsystem, pos, size);
53 }
54
55 ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size)
56 {
57         return get_sys_link(udev, "subsystem", syspath, subsystem, size);
58 }
59
60 ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size)
61 {
62         return get_sys_link(udev, "driver", syspath, driver, size);
63 }
64
65 int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
66 {
67         char link_target[UTIL_PATH_SIZE];
68
69         int len;
70         int i;
71         int back;
72
73         len = readlink(syspath, link_target, sizeof(link_target));
74         if (len <= 0)
75                 return -1;
76         link_target[len] = '\0';
77         dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
78
79         for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
80                 ;
81         dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
82         for (i = 0; i <= back; i++) {
83                 char *pos = strrchr(syspath, '/');
84
85                 if (pos == NULL)
86                         return -1;
87                 pos[0] = '\0';
88         }
89         dbg(udev, "after moving back '%s'\n", syspath);
90         util_strlcat(syspath, "/", size);
91         util_strlcat(syspath, &link_target[back * 3], size);
92         return 0;
93 }
94
95 struct util_name_entry *util_name_list_add(struct udev *udev, struct list_head *name_list,
96                                            const char *name, const char *value, int sort)
97 {
98         struct util_name_entry *name_loop;
99         struct util_name_entry *name_new;
100
101         /* avoid duplicate entries */
102         list_for_each_entry(name_loop, name_list, node) {
103                 if (strcmp(name_loop->name, name) == 0) {
104                         dbg(udev, "'%s' is already in the list\n", name);
105                         return name_loop;
106                 }
107         }
108
109         if (sort) {
110                 list_for_each_entry(name_loop, name_list, node) {
111                         if (strcmp(name_loop->name, name) > 0)
112                                 break;
113                 }
114         }
115
116         name_new = malloc(sizeof(struct util_name_entry));
117         if (name_new == NULL)
118                 return NULL;
119         memset(name_new, 0x00, sizeof(struct util_name_entry));
120         name_new->name = strdup(name);
121         if (name_new->name == NULL) {
122                 free(name_new);
123                 return NULL;
124         }
125         if (value != NULL) {
126                 name_new->value = strdup(value);
127                 if (name_new->value == NULL) {
128                         free(name_new);
129                         return NULL;
130                 }
131         }
132         dbg(udev, "adding '%s=%s'\n", name_new->name, name_new->value);
133         list_add_tail(&name_new->node, &name_loop->node);
134         return name_new;
135 }
136
137 void util_name_list_cleanup(struct udev *udev, struct list_head *name_list)
138 {
139         struct util_name_entry *name_loop;
140         struct util_name_entry *name_tmp;
141
142         list_for_each_entry_safe(name_loop, name_tmp, name_list, node) {
143                 list_del(&name_loop->node);
144                 free(name_loop->name);
145                 free(name_loop->value);
146                 free(name_loop);
147         }
148 }
149
150 int util_log_priority(const char *priority)
151 {
152         char *endptr;
153         int prio;
154
155         prio = strtol(priority, &endptr, 10);
156         if (endptr[0] == '\0')
157                 return prio;
158         if (strncasecmp(priority, "err", 3) == 0)
159                 return LOG_ERR;
160         if (strcasecmp(priority, "info") == 0)
161                 return LOG_INFO;
162         if (strcasecmp(priority, "debug") == 0)
163                 return LOG_DEBUG;
164         return 0;
165 }
166
167 size_t util_path_encode(char *s, size_t len)
168 {
169         char t[(len * 3)+1];
170         size_t i, j;
171
172         t[0] = '\0';
173         for (i = 0, j = 0; s[i] != '\0'; i++) {
174                 if (s[i] == '/') {
175                         memcpy(&t[j], "\\x2f", 4);
176                         j += 4;
177                 } else if (s[i] == '\\') {
178                         memcpy(&t[j], "\\x5c", 4);
179                         j += 4;
180                 } else {
181                         t[j] = s[i];
182                         j++;
183                 }
184         }
185         t[j] = '\0';
186         strncpy(s, t, len);
187         return j;
188 }
189
190 size_t util_path_decode(char *s)
191 {
192         size_t i, j;
193
194         for (i = 0, j = 0; s[i] != '\0'; j++) {
195                 if (memcmp(&s[i], "\\x2f", 4) == 0) {
196                         s[j] = '/';
197                         i += 4;
198                 }else if (memcmp(&s[i], "\\x5c", 4) == 0) {
199                         s[j] = '\\';
200                         i += 4;
201                 } else {
202                         s[j] = s[i];
203                         i++;
204                 }
205         }
206         s[j] = '\0';
207         return j;
208 }
209
210 void util_remove_trailing_chars(char *path, char c)
211 {
212         size_t len;
213
214         if (path == NULL)
215                 return;
216         len = strlen(path);
217         while (len > 0 && path[len-1] == c)
218                 path[--len] = '\0';
219 }
220
221 size_t util_strlcpy(char *dst, const char *src, size_t size)
222 {
223         size_t bytes = 0;
224         char *q = dst;
225         const char *p = src;
226         char ch;
227
228         while ((ch = *p++)) {
229                 if (bytes+1 < size)
230                         *q++ = ch;
231                 bytes++;
232         }
233
234         /* If size == 0 there is no space for a final null... */
235         if (size)
236                 *q = '\0';
237         return bytes;
238 }
239
240 size_t util_strlcat(char *dst, const char *src, size_t size)
241 {
242         size_t bytes = 0;
243         char *q = dst;
244         const char *p = src;
245         char ch;
246
247         while (bytes < size && *q) {
248                 q++;
249                 bytes++;
250         }
251         if (bytes == size)
252                 return (bytes + strlen(src));
253
254         while ((ch = *p++)) {
255                 if (bytes+1 < size)
256                 *q++ = ch;
257                 bytes++;
258         }
259
260         *q = '\0';
261         return bytes;
262 }
263
264 /* count of characters used to encode one unicode char */
265 static int utf8_encoded_expected_len(const char *str)
266 {
267         unsigned char c = (unsigned char)str[0];
268
269         if (c < 0x80)
270                 return 1;
271         if ((c & 0xe0) == 0xc0)
272                 return 2;
273         if ((c & 0xf0) == 0xe0)
274                 return 3;
275         if ((c & 0xf8) == 0xf0)
276                 return 4;
277         if ((c & 0xfc) == 0xf8)
278                 return 5;
279         if ((c & 0xfe) == 0xfc)
280                 return 6;
281         return 0;
282 }
283
284 /* decode one unicode char */
285 static int utf8_encoded_to_unichar(const char *str)
286 {
287         int unichar;
288         int len;
289         int i;
290
291         len = utf8_encoded_expected_len(str);
292         switch (len) {
293         case 1:
294                 return (int)str[0];
295         case 2:
296                 unichar = str[0] & 0x1f;
297                 break;
298         case 3:
299                 unichar = (int)str[0] & 0x0f;
300                 break;
301         case 4:
302                 unichar = (int)str[0] & 0x07;
303                 break;
304         case 5:
305                 unichar = (int)str[0] & 0x03;
306                 break;
307         case 6:
308                 unichar = (int)str[0] & 0x01;
309                 break;
310         default:
311                 return -1;
312         }
313
314         for (i = 1; i < len; i++) {
315                 if (((int)str[i] & 0xc0) != 0x80)
316                         return -1;
317                 unichar <<= 6;
318                 unichar |= (int)str[i] & 0x3f;
319         }
320
321         return unichar;
322 }
323
324 /* expected size used to encode one unicode char */
325 static int utf8_unichar_to_encoded_len(int unichar)
326 {
327         if (unichar < 0x80)
328                 return 1;
329         if (unichar < 0x800)
330                 return 2;
331         if (unichar < 0x10000)
332                 return 3;
333         if (unichar < 0x200000)
334                 return 4;
335         if (unichar < 0x4000000)
336                 return 5;
337         return 6;
338 }
339
340 /* check if unicode char has a valid numeric range */
341 static int utf8_unichar_valid_range(int unichar)
342 {
343         if (unichar > 0x10ffff)
344                 return 0;
345         if ((unichar & 0xfffff800) == 0xd800)
346                 return 0;
347         if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
348                 return 0;
349         if ((unichar & 0xffff) == 0xffff)
350                 return 0;
351         return 1;
352 }
353
354 /* validate one encoded unicode char and return its length */
355 static int utf8_encoded_valid_unichar(const char *str)
356 {
357         int len;
358         int unichar;
359         int i;
360
361         len = utf8_encoded_expected_len(str);
362         if (len == 0)
363                 return -1;
364
365         /* ascii is valid */
366         if (len == 1)
367                 return 1;
368
369         /* check if expected encoded chars are available */
370         for (i = 0; i < len; i++)
371                 if ((str[i] & 0x80) != 0x80)
372                         return -1;
373
374         unichar = utf8_encoded_to_unichar(str);
375
376         /* check if encoded length matches encoded value */
377         if (utf8_unichar_to_encoded_len(unichar) != len)
378                 return -1;
379
380         /* check if value has valid range */
381         if (!utf8_unichar_valid_range(unichar))
382                 return -1;
383
384         return len;
385 }
386
387 /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
388 int util_replace_chars(char *str, const char *white)
389 {
390         size_t i = 0;
391         int replaced = 0;
392
393         while (str[i] != '\0') {
394                 int len;
395
396                 /* accept whitelist */
397                 if (white != NULL && strchr(white, str[i]) != NULL) {
398                         i++;
399                         continue;
400                 }
401
402                 /* accept plain ascii char */
403                 if ((str[i] >= '0' && str[i] <= '9') ||
404                     (str[i] >= 'A' && str[i] <= 'Z') ||
405                     (str[i] >= 'a' && str[i] <= 'z')) {
406                         i++;
407                         continue;
408                 }
409
410                 /* accept hex encoding */
411                 if (str[i] == '\\' && str[i+1] == 'x') {
412                         i += 2;
413                         continue;
414                 }
415
416                 /* accept valid utf8 */
417                 len = utf8_encoded_valid_unichar(&str[i]);
418                 if (len > 1) {
419                         i += len;
420                         continue;
421                 }
422
423                 /* if space is allowed, replace whitespace with ordinary space */
424                 if (isspace(str[i]) && strchr(white, ' ') != NULL) {
425                         str[i] = ' ';
426                         i++;
427                         replaced++;
428                         continue;
429                 }
430
431                 /* everything else is replaced with '_' */
432                 str[i] = '_';
433                 i++;
434                 replaced++;
435         }
436
437         return replaced;
438 }