2 * libudev - interface to udev device information
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
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.
24 #include "libudev-private.h"
26 static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
28 char path[UTIL_PATH_SIZE];
32 util_strlcpy(path, syspath, sizeof(path));
33 util_strlcat(path, "/", sizeof(path));
34 util_strlcat(path, slink, sizeof(path));
35 len = readlink(path, path, sizeof(path));
36 if (len < 0 || len >= (ssize_t) sizeof(path))
39 pos = strrchr(path, '/');
43 dbg(udev, "resolved link to: '%s'\n", pos);
44 return util_strlcpy(value, pos, size);
47 ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size)
49 return get_sys_link(udev, "subsystem", syspath, subsystem, size);
52 ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size)
54 return get_sys_link(udev, "driver", syspath, driver, size);
57 int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
59 char link_target[UTIL_PATH_SIZE];
65 len = readlink(syspath, link_target, sizeof(link_target));
68 link_target[len] = '\0';
69 dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
71 for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
73 dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
74 for (i = 0; i <= back; i++) {
75 char *pos = strrchr(syspath, '/');
81 dbg(udev, "after moving back '%s'\n", syspath);
82 util_strlcat(syspath, "/", size);
83 util_strlcat(syspath, &link_target[back * 3], size);
87 int util_log_priority(const char *priority)
92 prio = strtol(priority, &endptr, 10);
93 if (endptr[0] == '\0')
95 if (strncasecmp(priority, "err", 3) == 0)
97 if (strcasecmp(priority, "info") == 0)
99 if (strcasecmp(priority, "debug") == 0)
104 size_t util_path_encode(char *s, size_t size)
106 char t[(size * 4)+1];
109 for (i = 0, j = 0; s[i] != '\0' && i < size; i++) {
111 memcpy(&t[j], "\\x2f", 4);
113 } else if (s[i] == '\\') {
114 memcpy(&t[j], "\\x5c", 4);
130 size_t util_path_decode(char *s)
134 for (i = 0, j = 0; s[i] != '\0'; j++) {
135 if (memcmp(&s[i], "\\x2f", 4) == 0) {
138 } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
150 void util_remove_trailing_chars(char *path, char c)
157 while (len > 0 && path[len-1] == c)
161 size_t util_strlcpy(char *dst, const char *src, size_t size)
168 while ((ch = *p++)) {
174 /* If size == 0 there is no space for a final null... */
180 size_t util_strlcat(char *dst, const char *src, size_t size)
187 while (bytes < size && *q) {
192 return (bytes + strlen(src));
194 while ((ch = *p++)) {
204 /* count of characters used to encode one unicode char */
205 static int utf8_encoded_expected_len(const char *str)
207 unsigned char c = (unsigned char)str[0];
211 if ((c & 0xe0) == 0xc0)
213 if ((c & 0xf0) == 0xe0)
215 if ((c & 0xf8) == 0xf0)
217 if ((c & 0xfc) == 0xf8)
219 if ((c & 0xfe) == 0xfc)
224 /* decode one unicode char */
225 static int utf8_encoded_to_unichar(const char *str)
231 len = utf8_encoded_expected_len(str);
236 unichar = str[0] & 0x1f;
239 unichar = (int)str[0] & 0x0f;
242 unichar = (int)str[0] & 0x07;
245 unichar = (int)str[0] & 0x03;
248 unichar = (int)str[0] & 0x01;
254 for (i = 1; i < len; i++) {
255 if (((int)str[i] & 0xc0) != 0x80)
258 unichar |= (int)str[i] & 0x3f;
264 /* expected size used to encode one unicode char */
265 static int utf8_unichar_to_encoded_len(int unichar)
271 if (unichar < 0x10000)
273 if (unichar < 0x200000)
275 if (unichar < 0x4000000)
280 /* check if unicode char has a valid numeric range */
281 static int utf8_unichar_valid_range(int unichar)
283 if (unichar > 0x10ffff)
285 if ((unichar & 0xfffff800) == 0xd800)
287 if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
289 if ((unichar & 0xffff) == 0xffff)
294 /* validate one encoded unicode char and return its length */
295 static int utf8_encoded_valid_unichar(const char *str)
301 len = utf8_encoded_expected_len(str);
309 /* check if expected encoded chars are available */
310 for (i = 0; i < len; i++)
311 if ((str[i] & 0x80) != 0x80)
314 unichar = utf8_encoded_to_unichar(str);
316 /* check if encoded length matches encoded value */
317 if (utf8_unichar_to_encoded_len(unichar) != len)
320 /* check if value has valid range */
321 if (!utf8_unichar_valid_range(unichar))
327 int udev_util_replace_whitespace(const char *str, char *to, size_t len)
331 /* strip trailing whitespace */
332 len = strnlen(str, len);
333 while (len && isspace(str[len-1]))
336 /* strip leading whitespace */
338 while (isspace(str[i]) && (i < len))
343 /* substitute multiple whitespace with a single '_' */
344 if (isspace(str[i])) {
345 while (isspace(str[i]))
355 static int is_whitelisted(char c, const char *white)
357 if ((c >= '0' && c <= '9') ||
358 (c >= 'A' && c <= 'Z') ||
359 (c >= 'a' && c <= 'z') ||
360 strchr("#+-.:=@_", c) != NULL ||
361 (white != NULL && strchr(white, c) != NULL))
366 /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
367 int udev_util_replace_chars(char *str, const char *white)
372 while (str[i] != '\0') {
375 if (is_whitelisted(str[i], white)) {
380 /* accept hex encoding */
381 if (str[i] == '\\' && str[i+1] == 'x') {
386 /* accept valid utf8 */
387 len = utf8_encoded_valid_unichar(&str[i]);
393 /* if space is allowed, replace whitespace with ordinary space */
394 if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
401 /* everything else is replaced with '_' */
410 * util_encode_string:
411 * @str: input string to be encoded
412 * @str_enc: output string to store the encoded input string
413 * @len: maximum size of the output string, which may be
414 * four times as long as the input string
416 * Encode all potentially unsafe characters of a string to the
417 * corresponding hex value prefixed by '\x'.
419 * Returns: 0 if the entire string was copied, non-zero otherwise.
421 int udev_util_encode_string(const char *str, char *str_enc, size_t len)
425 if (str == NULL || str_enc == NULL || len == 0)
429 for (i = 0, j = 0; str[i] != '\0'; i++) {
432 seqlen = utf8_encoded_valid_unichar(&str[i]);
434 memcpy(&str_enc[j], &str[i], seqlen);
437 } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
438 sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
453 void util_set_fd_cloexec(int fd)
457 flags = fcntl(fd, F_GETFD);
462 fcntl(fd, F_SETFD, flags);
465 unsigned int util_crc32(const unsigned char *buf, size_t len)
468 const unsigned char *end;
469 static const unsigned int crc32_table[256] = {
470 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
471 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
472 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
473 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
474 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
475 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
476 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
477 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
478 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
479 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
480 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
481 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
482 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
483 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
484 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
485 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
486 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
487 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
488 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
489 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
490 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
491 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
492 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
493 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
494 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
495 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
496 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
497 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
498 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
499 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
500 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
501 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
502 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
503 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
504 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
505 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
506 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
507 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
508 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
509 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
510 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
511 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
512 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
513 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
514 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
515 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
516 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
517 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
518 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
519 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
520 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
525 for (end = buf + len; buf < end; ++buf)
526 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);