X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibudev%2Flibudev-util.c;h=44f6e4a863b1df1f4f2bef99b5fb762fbb327e8c;hp=24d402cd2af67a0f862043c3a06aaefde09c58ff;hb=acd42fae59096d84e78f1c17bfcc0d8f96486341;hpb=33502ffe2eb7b56cdd018a4fb6830d7828519fad diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index 24d402cd2..44f6e4a86 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -1,13 +1,21 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2011 Kay Sievers - * - * 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 + + 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 . +***/ #include #include @@ -19,7 +27,10 @@ #include #include #include +#include +#include #include +#include #include "libudev.h" #include "libudev-private.h" @@ -27,8 +38,168 @@ /** * SECTION:libudev-util * @short_description: utils + * + * 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++; + 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 (streq(user, "root")) + 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 (streq(group, "root")) + 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 "[/]" format */ +int util_resolve_subsys_kernel(struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value) +{ + char temp[UTIL_PATH_SIZE]; + char *subsys; + char *sysname; + struct udev_device *dev; + char *attr; + + if (string[0] != '[') + return -1; + + strscpy(temp, sizeof(temp), string); + + subsys = &temp[1]; + + sysname = strchr(subsys, '/'); + if (sysname == NULL) + return -1; + sysname[0] = '\0'; + sysname = &sysname[1]; + + attr = strchr(sysname, ']'); + if (attr == NULL) + return -1; + attr[0] = '\0'; + attr = &attr[1]; + if (attr[0] == '/') + attr = &attr[1]; + if (attr[0] == '\0') + attr = NULL; + + if (read_value && attr == NULL) + return -1; + + dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); + if (dev == NULL) + return -1; + + if (read_value) { + const char *val; + + val = udev_device_get_sysattr_value(dev, attr); + if (val != NULL) + strscpy(result, maxsize, val); + else + result[0] = '\0'; + udev_dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); + } else { + size_t l; + char *s; + + s = result; + l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); + if (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]; @@ -36,7 +207,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; @@ -45,7 +216,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) @@ -72,7 +243,7 @@ int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) } 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; } @@ -125,26 +296,6 @@ size_t util_path_encode(const char *src, char *dest, size_t size) return j; } -size_t util_path_decode(char *s) -{ - size_t i, j; - - for (i = 0, j = 0; s[i] != '\0'; j++) { - if (memcmp(&s[i], "\\x2f", 4) == 0) { - s[j] = '/'; - i += 4; - } else if (memcmp(&s[i], "\\x5c", 4) == 0) { - s[j] = '\\'; - i += 4; - } else { - s[j] = s[i]; - i++; - } - } - s[j] = '\0'; - return j; -} - void util_remove_trailing_chars(char *path, char c) { size_t len; @@ -156,72 +307,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) { @@ -483,7 +568,7 @@ err: * Murmurhash is under the MIT license. * */ -static unsigned int murmur_hash2(const char *key, int len, unsigned int seed) +static unsigned int murmur_hash2(const char *key, size_t len, unsigned int seed) { /* * 'm' and 'r' are mixing constants generated offline. @@ -498,17 +583,18 @@ static unsigned int murmur_hash2(const char *key, int len, unsigned int seed) /* 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; + while(len >= sizeof(unsigned int)) { + unsigned int k; + memcpy(&k, data, sizeof(k)); k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; - data += 4; - len -= 4; + data += sizeof(k); + len -= sizeof(k); } /* handle the last few bytes of the input array */ @@ -548,19 +634,27 @@ uint64_t util_string_bloom64(const char *str) return bits; } -#define USEC_PER_SEC 1000000ULL -#define NSEC_PER_USEC 1000ULL -unsigned long long ts_usec(const struct timespec *ts) +ssize_t print_kmsg(const char *fmt, ...) { - return (unsigned long long) ts->tv_sec * USEC_PER_SEC + - (unsigned long long) ts->tv_nsec / NSEC_PER_USEC; -} + int fd; + va_list ap; + char text[1024]; + ssize_t len; + ssize_t ret; -unsigned long long now_usec(void) -{ - struct timespec ts; + fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - return 0; - return ts_usec(&ts); + 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; }