chiark / gitweb /
libudev: util - drop util_delete_path()
[elogind.git] / src / libudev / libudev-util.c
index b609857eafc90ad62a1efa4fa8ab15218d56fe79..a7125fa63f60964f1c5c7074167183395ad00afd 100644 (file)
@@ -1,13 +1,21 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- */
+/***
+  This file is part of systemd.
+
+  Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/param.h>
 
+#include "device-nodes.h"
 #include "libudev.h"
 #include "libudev-private.h"
+#include "utf8.h"
+#include "MurmurHash2.h"
 
 /**
  * SECTION:libudev-util
  * Utilities useful when dealing with devices and device node names.
  */
 
-int util_delete_path(struct udev *udev, const char *path)
-{
-        char p[UTIL_PATH_SIZE];
-        char *pos;
-        int err = 0;
-
-        if (path[0] == '/')
-                while(path[1] == '/')
-                        path++;
-        util_strscpy(p, sizeof(p), path);
-        pos = strrchr(p, '/');
-        if (pos == p || pos == NULL)
-                return 0;
-
-        for (;;) {
-                *pos = '\0';
-                pos = strrchr(p, '/');
-
-                /* don't remove the last one */
-                if ((pos == p) || (pos == NULL))
-                        break;
-
-                err = rmdir(p);
-                if (err < 0) {
-                        if (errno == ENOENT)
-                                err = 0;
-                        break;
-                }
-        }
-        return err;
-}
-
-uid_t util_lookup_user(struct udev *udev, const char *user)
-{
-        char *endptr;
-        struct passwd pwbuf;
-        struct passwd *pw;
-        uid_t uid;
-        size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
-        char *buf = alloca(buflen);
-
-        if (strcmp(user, "root") == 0)
-                return 0;
-        uid = strtoul(user, &endptr, 10);
-        if (endptr[0] == '\0')
-                return uid;
-
-        errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw);
-        if (pw != NULL)
-                return pw->pw_uid;
-        if (errno == 0 || errno == ENOENT || errno == ESRCH)
-                udev_err(udev, "specified user '%s' unknown\n", user);
-        else
-                udev_err(udev, "error resolving user '%s': %m\n", user);
-        return 0;
-}
-
-gid_t util_lookup_group(struct udev *udev, const char *group)
-{
-        char *endptr;
-        struct group grbuf;
-        struct group *gr;
-        gid_t gid = 0;
-        size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
-        char *buf = NULL;
-
-        if (strcmp(group, "root") == 0)
-                return 0;
-        gid = strtoul(group, &endptr, 10);
-        if (endptr[0] == '\0')
-                return gid;
-        gid = 0;
-        for (;;) {
-                char *newbuf;
-
-                newbuf = realloc(buf, buflen);
-                if (!newbuf)
-                        break;
-                buf = newbuf;
-                errno = getgrnam_r(group, &grbuf, buf, buflen, &gr);
-                if (gr != NULL) {
-                        gid = gr->gr_gid;
-                } else if (errno == ERANGE) {
-                        buflen *= 2;
-                        continue;
-                } else if (errno == 0 || errno == ENOENT || errno == ESRCH) {
-                        udev_err(udev, "specified group '%s' unknown\n", group);
-                } else {
-                        udev_err(udev, "error resolving group '%s': %m\n", group);
-                }
-                break;
-        }
-        free(buf);
-        return gid;
-}
-
 /* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
 int util_resolve_subsys_kernel(struct udev *udev, const char *string,
                                char *result, size_t maxsize, int read_value)
@@ -143,7 +58,7 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
         if (string[0] != '[')
                 return -1;
 
-        util_strscpy(temp, sizeof(temp), string);
+        strscpy(temp, sizeof(temp), string);
 
         subsys = &temp[1];
 
@@ -175,7 +90,7 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
 
                 val = udev_device_get_sysattr_value(dev, attr);
                 if (val != NULL)
-                        util_strscpy(result, maxsize, val);
+                        strscpy(result, maxsize, val);
                 else
                         result[0] = '\0';
                 udev_dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
@@ -184,14 +99,15 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
                 char *s;
 
                 s = result;
-                l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
+                l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
                 if (attr != NULL)
-                        util_strpcpyl(&s, l, "/", attr, NULL);
+                        strpcpyl(&s, l, "/", attr, NULL);
                 udev_dbg(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
         }
         udev_device_unref(dev);
         return 0;
 }
+
 ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
 {
         char path[UTIL_PATH_SIZE];
@@ -199,7 +115,7 @@ ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const
         ssize_t len;
         const char *pos;
 
-        util_strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
+        strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
         len = readlink(path, target, sizeof(target));
         if (len <= 0 || len == (ssize_t)sizeof(target))
                 return -1;
@@ -208,7 +124,7 @@ ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const
         if (pos == NULL)
                 return -1;
         pos = &pos[1];
-        return util_strscpy(value, size, pos);
+        return strscpy(value, size, pos);
 }
 
 int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
@@ -233,9 +149,8 @@ int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
                         return -EINVAL;
                 base[0] = '\0';
         }
-        if (base == NULL)
-                return -EINVAL;
-        util_strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
+
+        strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
         return 0;
 }
 
@@ -299,195 +214,6 @@ void util_remove_trailing_chars(char *path, char c)
                 path[--len] = '\0';
 }
 
-/*
- * Concatenates strings. In any case, terminates in _all_ cases with '\0'
- * and moves the @dest pointer forward to the added '\0'. Returns the
- * remaining size, and 0 if the string was truncated.
- */
-size_t util_strpcpy(char **dest, size_t size, const char *src)
-{
-        size_t len;
-
-        len = strlen(src);
-        if (len >= size) {
-                if (size > 1)
-                        *dest = mempcpy(*dest, src, size-1);
-                size = 0;
-                *dest[0] = '\0';
-        } else {
-                if (len > 0) {
-                        *dest = mempcpy(*dest, src, len);
-                        size -= len;
-                }
-                *dest[0] = '\0';
-        }
-        return size;
-}
-
-/* concatenates list of strings, moves dest forward */
-size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
-{
-        va_list va;
-
-        va_start(va, src);
-        do {
-                size = util_strpcpy(dest, size, src);
-                src = va_arg(va, char *);
-        } while (src != NULL);
-        va_end(va);
-
-        return size;
-}
-
-/* copies string */
-size_t util_strscpy(char *dest, size_t size, const char *src)
-{
-        char *s;
-
-        s = dest;
-        return util_strpcpy(&s, size, src);
-}
-
-/* concatenates list of strings */
-size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
-{
-        va_list va;
-        char *s;
-
-        va_start(va, src);
-        s = dest;
-        do {
-                size = util_strpcpy(&s, size, src);
-                src = va_arg(va, char *);
-        } while (src != NULL);
-        va_end(va);
-
-        return size;
-}
-
-/* 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;
-}
-
 int util_replace_whitespace(const char *str, char *to, size_t len)
 {
         size_t i, j;
@@ -516,17 +242,6 @@ int util_replace_whitespace(const char *str, char *to, size_t len)
         return 0;
 }
 
-static int is_whitelisted(char c, const char *white)
-{
-        if ((c >= '0' && c <= '9') ||
-            (c >= 'A' && c <= 'Z') ||
-            (c >= 'a' && c <= 'z') ||
-            strchr("#+-.:=@_", c) != NULL ||
-            (white != NULL && strchr(white, c) != NULL))
-                return 1;
-        return 0;
-}
-
 /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
 int util_replace_chars(char *str, const char *white)
 {
@@ -536,7 +251,7 @@ int util_replace_chars(char *str, const char *white)
         while (str[i] != '\0') {
                 int len;
 
-                if (is_whitelisted(str[i], white)) {
+                if (whitelisted_char_for_devnode(str[i], white)) {
                         i++;
                         continue;
                 }
@@ -584,98 +299,12 @@ int util_replace_chars(char *str, const char *white)
  **/
 _public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len)
 {
-        size_t i, j;
-
-        if (str == NULL || str_enc == NULL)
-                return -1;
-
-        for (i = 0, j = 0; str[i] != '\0'; i++) {
-                int seqlen;
-
-                seqlen = utf8_encoded_valid_unichar(&str[i]);
-                if (seqlen > 1) {
-                        if (len-j < (size_t)seqlen)
-                                goto err;
-                        memcpy(&str_enc[j], &str[i], seqlen);
-                        j += seqlen;
-                        i += (seqlen-1);
-                } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
-                        if (len-j < 4)
-                                goto err;
-                        sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
-                        j += 4;
-                } else {
-                        if (len-j < 1)
-                                goto err;
-                        str_enc[j] = str[i];
-                        j++;
-                }
-        }
-        if (len-j < 1)
-                goto err;
-        str_enc[j] = '\0';
-        return 0;
-err:
-        return -1;
-}
-
-/*
- * http://sites.google.com/site/murmurhash/
- *
- * All code is released to the public domain. For business purposes,
- * Murmurhash is under the MIT license.
- *
- */
-static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
-{
-        /*
-         *  'm' and 'r' are mixing constants generated offline.
-         *  They're not really 'magic', they just happen to work well.
-         */
-        const unsigned int m = 0x5bd1e995;
-        const int r = 24;
-
-        /* initialize the hash to a 'random' value */
-        unsigned int h = seed ^ len;
-
-        /* mix 4 bytes at a time into the hash */
-        const unsigned char * data = (const unsigned char *)key;
-
-        while(len >= 4) {
-                unsigned int k = *(unsigned int *)data;
-
-                k *= m;
-                k ^= k >> r;
-                k *= m;
-                h *= m;
-                h ^= k;
-
-                data += 4;
-                len -= 4;
-        }
-
-        /* handle the last few bytes of the input array */
-        switch(len) {
-        case 3:
-                h ^= data[2] << 16;
-        case 2:
-                h ^= data[1] << 8;
-        case 1:
-                h ^= data[0];
-                h *= m;
-        };
-
-        /* do a few final mixes of the hash to ensure the last few bytes are well-incorporated */
-        h ^= h >> 13;
-        h *= m;
-        h ^= h >> 15;
-
-        return h;
+        return encode_devnode_name(str, str_enc, len);
 }
 
 unsigned int util_string_hash32(const char *str)
 {
-        return murmur_hash2(str, strlen(str), 0);
+        return MurmurHash2(str, strlen(str), 0);
 }
 
 /* get a bunch of bit numbers out of the hash, and set the bits in our bit field */
@@ -690,28 +319,3 @@ uint64_t util_string_bloom64(const char *str)
         bits |= 1LLU << ((hash >> 18) & 63);
         return bits;
 }
-
-ssize_t print_kmsg(const char *fmt, ...)
-{
-        int fd;
-        va_list ap;
-        char text[1024];
-        ssize_t len;
-        ssize_t ret;
-
-        fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        len = snprintf(text, sizeof(text), "<30>systemd-udevd[%u]: ", getpid());
-
-        va_start(ap, fmt);
-        len += vsnprintf(text + len, sizeof(text) - len, fmt, ap);
-        va_end(ap);
-
-        ret = write(fd, text, len);
-        if (ret < 0)
-                ret = -errno;
-        close(fd);
-        return ret;
-}