#include <errno.h>
#include <string.h>
#include <dirent.h>
+#include <ctype.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include "libudev.h"
#include "libudev-private.h"
-static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *devpath, char *subsystem, size_t size)
+static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *syspath, char *subsystem, size_t size)
{
char path[UTIL_PATH_SIZE];
ssize_t len;
const char *pos;
- util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
- util_strlcat(path, devpath, sizeof(path));
+ util_strlcpy(path, syspath, sizeof(path));
util_strlcat(path, "/", sizeof(path));
util_strlcat(path, slink, sizeof(path));
len = readlink(path, path, sizeof(path));
return util_strlcpy(subsystem, pos, size);
}
-ssize_t util_get_sys_subsystem(struct udev *udev, const char *devpath, char *subsystem, size_t size)
+ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size)
{
- return get_sys_link(udev, "subsystem", devpath, subsystem, size);
+ return get_sys_link(udev, "subsystem", syspath, subsystem, size);
}
-ssize_t util_get_sys_driver(struct udev *udev, const char *devpath, char *driver, size_t size)
+ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size)
{
- return get_sys_link(udev, "driver", devpath, driver, size);
+ return get_sys_link(udev, "driver", syspath, driver, size);
}
-int util_resolve_sys_link(struct udev *udev, char *devpath, size_t size)
+int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
{
- char link_path[UTIL_PATH_SIZE];
char link_target[UTIL_PATH_SIZE];
int len;
int i;
int back;
- util_strlcpy(link_path, udev_get_sys_path(udev), sizeof(link_path));
- util_strlcat(link_path, devpath, sizeof(link_path));
- len = readlink(link_path, link_target, sizeof(link_target));
+ len = readlink(syspath, link_target, sizeof(link_target));
if (len <= 0)
return -1;
link_target[len] = '\0';
- dbg(udev, "path link '%s' points to '%s'\n", devpath, link_target);
+ dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
;
- dbg(udev, "base '%s', tail '%s', back %i\n", devpath, &link_target[back * 3], back);
+ dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
for (i = 0; i <= back; i++) {
- char *pos = strrchr(devpath, '/');
+ char *pos = strrchr(syspath, '/');
if (pos == NULL)
return -1;
pos[0] = '\0';
}
- dbg(udev, "after moving back '%s'\n", devpath);
- util_strlcat(devpath, "/", size);
- util_strlcat(devpath, &link_target[back * 3], size);
+ dbg(udev, "after moving back '%s'\n", syspath);
+ util_strlcat(syspath, "/", size);
+ util_strlcat(syspath, &link_target[back * 3], size);
return 0;
}
struct util_name_entry *util_name_list_add(struct udev *udev, struct list_head *name_list,
- const char *name, int sort)
+ const char *name, const char *value, int sort)
{
struct util_name_entry *name_loop;
struct util_name_entry *name_new;
free(name_new);
return NULL;
}
- dbg(udev, "adding '%s'\n", name_new->name);
+ if (value != NULL) {
+ name_new->value = strdup(value);
+ if (name_new->value == NULL) {
+ free(name_new);
+ return NULL;
+ }
+ }
+ dbg(udev, "adding '%s=%s'\n", name_new->name, name_new->value);
list_add_tail(&name_new->node, &name_loop->node);
return name_new;
}
list_for_each_entry_safe(name_loop, name_tmp, name_list, node) {
list_del(&name_loop->node);
free(name_loop->name);
+ free(name_loop->value);
free(name_loop);
}
}
*q = '\0';
return bytes;
}
+
+/* count of characters used to encode one unicode char */
+static int utf8_encoded_expected_len(const char *str)
+{
+ unsigned char c = (unsigned char)str[0];
+
+ if (c < 0x80)
+ return 1;
+ if ((c & 0xe0) == 0xc0)
+ return 2;
+ if ((c & 0xf0) == 0xe0)
+ return 3;
+ if ((c & 0xf8) == 0xf0)
+ return 4;
+ if ((c & 0xfc) == 0xf8)
+ return 5;
+ if ((c & 0xfe) == 0xfc)
+ return 6;
+ return 0;
+}
+
+/* decode one unicode char */
+static int utf8_encoded_to_unichar(const char *str)
+{
+ int unichar;
+ int len;
+ int i;
+
+ len = utf8_encoded_expected_len(str);
+ switch (len) {
+ case 1:
+ return (int)str[0];
+ case 2:
+ unichar = str[0] & 0x1f;
+ break;
+ case 3:
+ unichar = (int)str[0] & 0x0f;
+ break;
+ case 4:
+ unichar = (int)str[0] & 0x07;
+ break;
+ case 5:
+ unichar = (int)str[0] & 0x03;
+ break;
+ case 6:
+ unichar = (int)str[0] & 0x01;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i = 1; i < len; i++) {
+ if (((int)str[i] & 0xc0) != 0x80)
+ return -1;
+ unichar <<= 6;
+ unichar |= (int)str[i] & 0x3f;
+ }
+
+ return unichar;
+}
+
+/* expected size used to encode one unicode char */
+static int utf8_unichar_to_encoded_len(int unichar)
+{
+ if (unichar < 0x80)
+ return 1;
+ if (unichar < 0x800)
+ return 2;
+ if (unichar < 0x10000)
+ return 3;
+ if (unichar < 0x200000)
+ return 4;
+ if (unichar < 0x4000000)
+ return 5;
+ return 6;
+}
+
+/* check if unicode char has a valid numeric range */
+static int utf8_unichar_valid_range(int unichar)
+{
+ if (unichar > 0x10ffff)
+ return 0;
+ if ((unichar & 0xfffff800) == 0xd800)
+ return 0;
+ if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
+ return 0;
+ if ((unichar & 0xffff) == 0xffff)
+ return 0;
+ return 1;
+}
+
+/* validate one encoded unicode char and return its length */
+static int utf8_encoded_valid_unichar(const char *str)
+{
+ int len;
+ int unichar;
+ int i;
+
+ len = utf8_encoded_expected_len(str);
+ if (len == 0)
+ return -1;
+
+ /* ascii is valid */
+ if (len == 1)
+ return 1;
+
+ /* check if expected encoded chars are available */
+ for (i = 0; i < len; i++)
+ if ((str[i] & 0x80) != 0x80)
+ return -1;
+
+ unichar = utf8_encoded_to_unichar(str);
+
+ /* check if encoded length matches encoded value */
+ if (utf8_unichar_to_encoded_len(unichar) != len)
+ return -1;
+
+ /* check if value has valid range */
+ if (!utf8_unichar_valid_range(unichar))
+ return -1;
+
+ return len;
+}
+
+/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
+int util_replace_chars(char *str, const char *white)
+{
+ size_t i = 0;
+ int replaced = 0;
+
+ while (str[i] != '\0') {
+ int len;
+
+ /* accept whitelist */
+ if (white != NULL && strchr(white, str[i]) != NULL) {
+ i++;
+ continue;
+ }
+
+ /* accept plain ascii char */
+ if ((str[i] >= '0' && str[i] <= '9') ||
+ (str[i] >= 'A' && str[i] <= 'Z') ||
+ (str[i] >= 'a' && str[i] <= 'z')) {
+ i++;
+ continue;
+ }
+
+ /* accept hex encoding */
+ if (str[i] == '\\' && str[i+1] == 'x') {
+ i += 2;
+ continue;
+ }
+
+ /* accept valid utf8 */
+ len = utf8_encoded_valid_unichar(&str[i]);
+ if (len > 1) {
+ i += len;
+ continue;
+ }
+
+ /* if space is allowed, replace whitespace with ordinary space */
+ if (isspace(str[i]) && strchr(white, ' ') != NULL) {
+ str[i] = ' ';
+ i++;
+ replaced++;
+ continue;
+ }
+
+ /* everything else is replaced with '_' */
+ str[i] = '_';
+ i++;
+ replaced++;
+ }
+
+ return replaced;
+}