chiark / gitweb /
timedated: replace systemd-timedated-ntp.target logic with simpler scheme
[elogind.git] / src / libudev / libudev-util.c
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <time.h>
22 #include <pwd.h>
23 #include <grp.h>
24 #include <sys/stat.h>
25 #include <sys/param.h>
26
27 #include "libudev.h"
28 #include "libudev-private.h"
29
30 /**
31  * SECTION:libudev-util
32  * @short_description: utils
33  *
34  * Utilities useful when dealing with devices and device node names.
35  */
36
37 int util_delete_path(struct udev *udev, const char *path)
38 {
39         char p[UTIL_PATH_SIZE];
40         char *pos;
41         int err = 0;
42
43         if (path[0] == '/')
44                 while(path[1] == '/')
45                         path++;
46         util_strscpy(p, sizeof(p), path);
47         pos = strrchr(p, '/');
48         if (pos == p || pos == NULL)
49                 return 0;
50
51         for (;;) {
52                 *pos = '\0';
53                 pos = strrchr(p, '/');
54
55                 /* don't remove the last one */
56                 if ((pos == p) || (pos == NULL))
57                         break;
58
59                 err = rmdir(p);
60                 if (err < 0) {
61                         if (errno == ENOENT)
62                                 err = 0;
63                         break;
64                 }
65         }
66         return err;
67 }
68
69 uid_t util_lookup_user(struct udev *udev, const char *user)
70 {
71         char *endptr;
72         struct passwd pwbuf;
73         struct passwd *pw;
74         uid_t uid;
75         size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
76         char *buf = alloca(buflen);
77
78         if (strcmp(user, "root") == 0)
79                 return 0;
80         uid = strtoul(user, &endptr, 10);
81         if (endptr[0] == '\0')
82                 return uid;
83
84         errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw);
85         if (pw != NULL)
86                 return pw->pw_uid;
87         if (errno == 0 || errno == ENOENT || errno == ESRCH)
88                 udev_err(udev, "specified user '%s' unknown\n", user);
89         else
90                 udev_err(udev, "error resolving user '%s': %m\n", user);
91         return 0;
92 }
93
94 gid_t util_lookup_group(struct udev *udev, const char *group)
95 {
96         char *endptr;
97         struct group grbuf;
98         struct group *gr;
99         gid_t gid = 0;
100         size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
101         char *buf = NULL;
102
103         if (strcmp(group, "root") == 0)
104                 return 0;
105         gid = strtoul(group, &endptr, 10);
106         if (endptr[0] == '\0')
107                 return gid;
108         gid = 0;
109         for (;;) {
110                 char *newbuf;
111
112                 newbuf = realloc(buf, buflen);
113                 if (!newbuf)
114                         break;
115                 buf = newbuf;
116                 errno = getgrnam_r(group, &grbuf, buf, buflen, &gr);
117                 if (gr != NULL) {
118                         gid = gr->gr_gid;
119                 } else if (errno == ERANGE) {
120                         buflen *= 2;
121                         continue;
122                 } else if (errno == 0 || errno == ENOENT || errno == ESRCH) {
123                         udev_err(udev, "specified group '%s' unknown\n", group);
124                 } else {
125                         udev_err(udev, "error resolving group '%s': %m\n", group);
126                 }
127                 break;
128         }
129         free(buf);
130         return gid;
131 }
132
133 /* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
134 int util_resolve_subsys_kernel(struct udev *udev, const char *string,
135                                char *result, size_t maxsize, int read_value)
136 {
137         char temp[UTIL_PATH_SIZE];
138         char *subsys;
139         char *sysname;
140         struct udev_device *dev;
141         char *attr;
142
143         if (string[0] != '[')
144                 return -1;
145
146         util_strscpy(temp, sizeof(temp), string);
147
148         subsys = &temp[1];
149
150         sysname = strchr(subsys, '/');
151         if (sysname == NULL)
152                 return -1;
153         sysname[0] = '\0';
154         sysname = &sysname[1];
155
156         attr = strchr(sysname, ']');
157         if (attr == NULL)
158                 return -1;
159         attr[0] = '\0';
160         attr = &attr[1];
161         if (attr[0] == '/')
162                 attr = &attr[1];
163         if (attr[0] == '\0')
164                 attr = NULL;
165
166         if (read_value && attr == NULL)
167                 return -1;
168
169         dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
170         if (dev == NULL)
171                 return -1;
172
173         if (read_value) {
174                 const char *val;
175
176                 val = udev_device_get_sysattr_value(dev, attr);
177                 if (val != NULL)
178                         util_strscpy(result, maxsize, val);
179                 else
180                         result[0] = '\0';
181                 udev_dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
182         } else {
183                 size_t l;
184                 char *s;
185
186                 s = result;
187                 l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
188                 if (attr != NULL)
189                         util_strpcpyl(&s, l, "/", attr, NULL);
190                 udev_dbg(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
191         }
192         udev_device_unref(dev);
193         return 0;
194 }
195 ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
196 {
197         char path[UTIL_PATH_SIZE];
198         char target[UTIL_PATH_SIZE];
199         ssize_t len;
200         const char *pos;
201
202         util_strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
203         len = readlink(path, target, sizeof(target));
204         if (len <= 0 || len == (ssize_t)sizeof(target))
205                 return -1;
206         target[len] = '\0';
207         pos = strrchr(target, '/');
208         if (pos == NULL)
209                 return -1;
210         pos = &pos[1];
211         return util_strscpy(value, size, pos);
212 }
213
214 int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
215 {
216         char link_target[UTIL_PATH_SIZE];
217
218         ssize_t len;
219         int i;
220         int back;
221         char *base = NULL;
222
223         len = readlink(syspath, link_target, sizeof(link_target));
224         if (len <= 0 || len == (ssize_t)sizeof(link_target))
225                 return -1;
226         link_target[len] = '\0';
227
228         for (back = 0; startswith(&link_target[back * 3], "../"); back++)
229                 ;
230         for (i = 0; i <= back; i++) {
231                 base = strrchr(syspath, '/');
232                 if (base == NULL)
233                         return -EINVAL;
234                 base[0] = '\0';
235         }
236         if (base == NULL)
237                 return -EINVAL;
238         util_strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
239         return 0;
240 }
241
242 int util_log_priority(const char *priority)
243 {
244         char *endptr;
245         int prio;
246
247         prio = strtol(priority, &endptr, 10);
248         if (endptr[0] == '\0' || isspace(endptr[0]))
249                 return prio;
250         if (startswith(priority, "err"))
251                 return LOG_ERR;
252         if (startswith(priority, "info"))
253                 return LOG_INFO;
254         if (startswith(priority, "debug"))
255                 return LOG_DEBUG;
256         return 0;
257 }
258
259 size_t util_path_encode(const char *src, char *dest, size_t size)
260 {
261         size_t i, j;
262
263         for (i = 0, j = 0; src[i] != '\0'; i++) {
264                 if (src[i] == '/') {
265                         if (j+4 >= size) {
266                                 j = 0;
267                                 break;
268                         }
269                         memcpy(&dest[j], "\\x2f", 4);
270                         j += 4;
271                 } else if (src[i] == '\\') {
272                         if (j+4 >= size) {
273                                 j = 0;
274                                 break;
275                         }
276                         memcpy(&dest[j], "\\x5c", 4);
277                         j += 4;
278                 } else {
279                         if (j+1 >= size) {
280                                 j = 0;
281                                 break;
282                         }
283                         dest[j] = src[i];
284                         j++;
285                 }
286         }
287         dest[j] = '\0';
288         return j;
289 }
290
291 size_t util_path_decode(char *s)
292 {
293         size_t i, j;
294
295         for (i = 0, j = 0; s[i] != '\0'; j++) {
296                 if (memcmp(&s[i], "\\x2f", 4) == 0) {
297                         s[j] = '/';
298                         i += 4;
299                 } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
300                         s[j] = '\\';
301                         i += 4;
302                 } else {
303                         s[j] = s[i];
304                         i++;
305                 }
306         }
307         s[j] = '\0';
308         return j;
309 }
310
311 void util_remove_trailing_chars(char *path, char c)
312 {
313         size_t len;
314
315         if (path == NULL)
316                 return;
317         len = strlen(path);
318         while (len > 0 && path[len-1] == c)
319                 path[--len] = '\0';
320 }
321
322 /*
323  * Concatenates strings. In any case, terminates in _all_ cases with '\0'
324  * and moves the @dest pointer forward to the added '\0'. Returns the
325  * remaining size, and 0 if the string was truncated.
326  */
327 size_t util_strpcpy(char **dest, size_t size, const char *src)
328 {
329         size_t len;
330
331         len = strlen(src);
332         if (len >= size) {
333                 if (size > 1)
334                         *dest = mempcpy(*dest, src, size-1);
335                 size = 0;
336                 *dest[0] = '\0';
337         } else {
338                 if (len > 0) {
339                         *dest = mempcpy(*dest, src, len);
340                         size -= len;
341                 }
342                 *dest[0] = '\0';
343         }
344         return size;
345 }
346
347 /* concatenates list of strings, moves dest forward */
348 size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
349 {
350         va_list va;
351
352         va_start(va, src);
353         do {
354                 size = util_strpcpy(dest, size, src);
355                 src = va_arg(va, char *);
356         } while (src != NULL);
357         va_end(va);
358
359         return size;
360 }
361
362 /* copies string */
363 size_t util_strscpy(char *dest, size_t size, const char *src)
364 {
365         char *s;
366
367         s = dest;
368         return util_strpcpy(&s, size, src);
369 }
370
371 /* concatenates list of strings */
372 size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
373 {
374         va_list va;
375         char *s;
376
377         va_start(va, src);
378         s = dest;
379         do {
380                 size = util_strpcpy(&s, size, src);
381                 src = va_arg(va, char *);
382         } while (src != NULL);
383         va_end(va);
384
385         return size;
386 }
387
388 /* count of characters used to encode one unicode char */
389 static int utf8_encoded_expected_len(const char *str)
390 {
391         unsigned char c = (unsigned char)str[0];
392
393         if (c < 0x80)
394                 return 1;
395         if ((c & 0xe0) == 0xc0)
396                 return 2;
397         if ((c & 0xf0) == 0xe0)
398                 return 3;
399         if ((c & 0xf8) == 0xf0)
400                 return 4;
401         if ((c & 0xfc) == 0xf8)
402                 return 5;
403         if ((c & 0xfe) == 0xfc)
404                 return 6;
405         return 0;
406 }
407
408 /* decode one unicode char */
409 static int utf8_encoded_to_unichar(const char *str)
410 {
411         int unichar;
412         int len;
413         int i;
414
415         len = utf8_encoded_expected_len(str);
416         switch (len) {
417         case 1:
418                 return (int)str[0];
419         case 2:
420                 unichar = str[0] & 0x1f;
421                 break;
422         case 3:
423                 unichar = (int)str[0] & 0x0f;
424                 break;
425         case 4:
426                 unichar = (int)str[0] & 0x07;
427                 break;
428         case 5:
429                 unichar = (int)str[0] & 0x03;
430                 break;
431         case 6:
432                 unichar = (int)str[0] & 0x01;
433                 break;
434         default:
435                 return -1;
436         }
437
438         for (i = 1; i < len; i++) {
439                 if (((int)str[i] & 0xc0) != 0x80)
440                         return -1;
441                 unichar <<= 6;
442                 unichar |= (int)str[i] & 0x3f;
443         }
444
445         return unichar;
446 }
447
448 /* expected size used to encode one unicode char */
449 static int utf8_unichar_to_encoded_len(int unichar)
450 {
451         if (unichar < 0x80)
452                 return 1;
453         if (unichar < 0x800)
454                 return 2;
455         if (unichar < 0x10000)
456                 return 3;
457         if (unichar < 0x200000)
458                 return 4;
459         if (unichar < 0x4000000)
460                 return 5;
461         return 6;
462 }
463
464 /* check if unicode char has a valid numeric range */
465 static int utf8_unichar_valid_range(int unichar)
466 {
467         if (unichar > 0x10ffff)
468                 return 0;
469         if ((unichar & 0xfffff800) == 0xd800)
470                 return 0;
471         if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
472                 return 0;
473         if ((unichar & 0xffff) == 0xffff)
474                 return 0;
475         return 1;
476 }
477
478 /* validate one encoded unicode char and return its length */
479 static int utf8_encoded_valid_unichar(const char *str)
480 {
481         int len;
482         int unichar;
483         int i;
484
485         len = utf8_encoded_expected_len(str);
486         if (len == 0)
487                 return -1;
488
489         /* ascii is valid */
490         if (len == 1)
491                 return 1;
492
493         /* check if expected encoded chars are available */
494         for (i = 0; i < len; i++)
495                 if ((str[i] & 0x80) != 0x80)
496                         return -1;
497
498         unichar = utf8_encoded_to_unichar(str);
499
500         /* check if encoded length matches encoded value */
501         if (utf8_unichar_to_encoded_len(unichar) != len)
502                 return -1;
503
504         /* check if value has valid range */
505         if (!utf8_unichar_valid_range(unichar))
506                 return -1;
507
508         return len;
509 }
510
511 int util_replace_whitespace(const char *str, char *to, size_t len)
512 {
513         size_t i, j;
514
515         /* strip trailing whitespace */
516         len = strnlen(str, len);
517         while (len && isspace(str[len-1]))
518                 len--;
519
520         /* strip leading whitespace */
521         i = 0;
522         while (isspace(str[i]) && (i < len))
523                 i++;
524
525         j = 0;
526         while (i < len) {
527                 /* substitute multiple whitespace with a single '_' */
528                 if (isspace(str[i])) {
529                         while (isspace(str[i]))
530                                 i++;
531                         to[j++] = '_';
532                 }
533                 to[j++] = str[i++];
534         }
535         to[j] = '\0';
536         return 0;
537 }
538
539 static int is_whitelisted(char c, const char *white)
540 {
541         if ((c >= '0' && c <= '9') ||
542             (c >= 'A' && c <= 'Z') ||
543             (c >= 'a' && c <= 'z') ||
544             strchr("#+-.:=@_", c) != NULL ||
545             (white != NULL && strchr(white, c) != NULL))
546                 return 1;
547         return 0;
548 }
549
550 /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
551 int util_replace_chars(char *str, const char *white)
552 {
553         size_t i = 0;
554         int replaced = 0;
555
556         while (str[i] != '\0') {
557                 int len;
558
559                 if (is_whitelisted(str[i], white)) {
560                         i++;
561                         continue;
562                 }
563
564                 /* accept hex encoding */
565                 if (str[i] == '\\' && str[i+1] == 'x') {
566                         i += 2;
567                         continue;
568                 }
569
570                 /* accept valid utf8 */
571                 len = utf8_encoded_valid_unichar(&str[i]);
572                 if (len > 1) {
573                         i += len;
574                         continue;
575                 }
576
577                 /* if space is allowed, replace whitespace with ordinary space */
578                 if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
579                         str[i] = ' ';
580                         i++;
581                         replaced++;
582                         continue;
583                 }
584
585                 /* everything else is replaced with '_' */
586                 str[i] = '_';
587                 i++;
588                 replaced++;
589         }
590         return replaced;
591 }
592
593 /**
594  * udev_util_encode_string:
595  * @str: input string to be encoded
596  * @str_enc: output string to store the encoded input string
597  * @len: maximum size of the output string, which may be
598  *       four times as long as the input string
599  *
600  * Encode all potentially unsafe characters of a string to the
601  * corresponding 2 char hex value prefixed by '\x'.
602  *
603  * Returns: 0 if the entire string was copied, non-zero otherwise.
604  **/
605 _public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len)
606 {
607         size_t i, j;
608
609         if (str == NULL || str_enc == NULL)
610                 return -1;
611
612         for (i = 0, j = 0; str[i] != '\0'; i++) {
613                 int seqlen;
614
615                 seqlen = utf8_encoded_valid_unichar(&str[i]);
616                 if (seqlen > 1) {
617                         if (len-j < (size_t)seqlen)
618                                 goto err;
619                         memcpy(&str_enc[j], &str[i], seqlen);
620                         j += seqlen;
621                         i += (seqlen-1);
622                 } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
623                         if (len-j < 4)
624                                 goto err;
625                         sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
626                         j += 4;
627                 } else {
628                         if (len-j < 1)
629                                 goto err;
630                         str_enc[j] = str[i];
631                         j++;
632                 }
633         }
634         if (len-j < 1)
635                 goto err;
636         str_enc[j] = '\0';
637         return 0;
638 err:
639         return -1;
640 }
641
642 /*
643  * http://sites.google.com/site/murmurhash/
644  *
645  * All code is released to the public domain. For business purposes,
646  * Murmurhash is under the MIT license.
647  *
648  */
649 static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
650 {
651         /*
652          *  'm' and 'r' are mixing constants generated offline.
653          *  They're not really 'magic', they just happen to work well.
654          */
655         const unsigned int m = 0x5bd1e995;
656         const int r = 24;
657
658         /* initialize the hash to a 'random' value */
659         unsigned int h = seed ^ len;
660
661         /* mix 4 bytes at a time into the hash */
662         const unsigned char * data = (const unsigned char *)key;
663
664         while(len >= 4) {
665                 unsigned int k = *(unsigned int *)data;
666
667                 k *= m;
668                 k ^= k >> r;
669                 k *= m;
670                 h *= m;
671                 h ^= k;
672
673                 data += 4;
674                 len -= 4;
675         }
676
677         /* handle the last few bytes of the input array */
678         switch(len) {
679         case 3:
680                 h ^= data[2] << 16;
681         case 2:
682                 h ^= data[1] << 8;
683         case 1:
684                 h ^= data[0];
685                 h *= m;
686         };
687
688         /* do a few final mixes of the hash to ensure the last few bytes are well-incorporated */
689         h ^= h >> 13;
690         h *= m;
691         h ^= h >> 15;
692
693         return h;
694 }
695
696 unsigned int util_string_hash32(const char *str)
697 {
698         return murmur_hash2(str, strlen(str), 0);
699 }
700
701 /* get a bunch of bit numbers out of the hash, and set the bits in our bit field */
702 uint64_t util_string_bloom64(const char *str)
703 {
704         uint64_t bits = 0;
705         unsigned int hash = util_string_hash32(str);
706
707         bits |= 1LLU << (hash & 63);
708         bits |= 1LLU << ((hash >> 6) & 63);
709         bits |= 1LLU << ((hash >> 12) & 63);
710         bits |= 1LLU << ((hash >> 18) & 63);
711         return bits;
712 }
713
714 #define USEC_PER_SEC  1000000ULL
715 #define NSEC_PER_USEC 1000ULL
716 unsigned long long ts_usec(const struct timespec *ts)
717 {
718         return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
719                (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
720 }
721
722 unsigned long long now_usec(void)
723 {
724         struct timespec ts;
725
726         if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
727                 return 0;
728         return ts_usec(&ts);
729 }