From b8ed8b124aaff754e244dff6930b36c192fa69e0 Mon Sep 17 00:00:00 2001 From: "Anthony G. Basile" Date: Tue, 14 Jan 2014 12:20:25 -0500 Subject: src/libudev: bring in line with upstream Signed-off-by: Anthony G. Basile --- src/libudev/Makefile.am | 2 + src/libudev/cgroup-util.c | 6 +- src/libudev/conf-files.c | 12 +-- src/libudev/def.h | 5 ++ src/libudev/hashmap.c | 172 +++++++++++++++++++++++++++--------- src/libudev/hashmap.h | 8 +- src/libudev/libudev-queue-private.c | 13 ++- src/libudev/libudev-util.c | 9 +- src/libudev/log.c | 55 ++++++++---- src/libudev/log.h | 24 +++-- src/libudev/macro.h | 46 ++++++---- src/libudev/path-util.c | 43 ++++----- src/libudev/path-util.h | 2 +- src/libudev/siphash24.c | 135 ++++++++++++++++++++++++++++ src/libudev/siphash24.h | 4 + src/libudev/socket-util.h | 14 +-- src/libudev/sparse-endian.h | 1 - src/libudev/strv.c | 12 +-- src/libudev/strv.h | 1 + src/libudev/strxcpyx.c | 12 +-- src/libudev/util.c | 105 ++++++++++++++++++++-- src/libudev/util.h | 11 +-- 22 files changed, 524 insertions(+), 168 deletions(-) create mode 100644 src/libudev/siphash24.c create mode 100644 src/libudev/siphash24.h (limited to 'src/libudev') diff --git a/src/libudev/Makefile.am b/src/libudev/Makefile.am index 286dc4b62a..84d018ae03 100644 --- a/src/libudev/Makefile.am +++ b/src/libudev/Makefile.am @@ -43,6 +43,7 @@ libudev_la_SOURCES =\ MurmurHash2.c \ path-util.c \ set.c \ + siphash24.c \ strbuf.c \ strv.c \ strxcpyx.c \ @@ -66,6 +67,7 @@ noinst_HEADERS = \ MurmurHash2.h \ path-util.h \ set.h \ + siphash24.h \ socket-util.h \ sparse-endian.h \ strbuf.h \ diff --git a/src/libudev/cgroup-util.c b/src/libudev/cgroup-util.c index 71bd529ad2..af6ce959c1 100644 --- a/src/libudev/cgroup-util.c +++ b/src/libudev/cgroup-util.c @@ -198,7 +198,7 @@ static int join_path(const char *controller, const char *path, const char *suffi int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) { const char *p; - static __thread bool good = false; + static thread_local bool good = false; assert(fs); @@ -223,9 +223,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch #define CONTROLLER_VALID \ - "0123456789" \ - "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + DIGITS LETTERS \ "_" bool cg_controller_is_valid(const char *p, bool allow_named) { diff --git a/src/libudev/conf-files.c b/src/libudev/conf-files.c index 2d413999f9..dc4f970313 100644 --- a/src/libudev/conf-files.c +++ b/src/libudev/conf-files.c @@ -53,13 +53,13 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char for (;;) { struct dirent *de; - union dirent_storage buf; char *p; int r; - r = readdir_r(dir, &buf.de, &de); - if (r != 0) - return -r; + errno = 0; + de = readdir(dir); + if (!de && errno != 0) + return -errno; if (!de) break; @@ -71,7 +71,7 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char if (!p) return -ENOMEM; - r = hashmap_put(h, path_get_file_name(p), p); + r = hashmap_put(h, basename(p), p); if (r == -EEXIST) { log_debug("Skipping overridden file: %s.", p); free(p); @@ -92,7 +92,7 @@ static int base_cmp(const void *a, const void *b) { s1 = *(char * const *)a; s2 = *(char * const *)b; - return strcmp(path_get_file_name(s1), path_get_file_name(s2)); + return strcmp(basename(s1), basename(s2)); } static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) { diff --git a/src/libudev/def.h b/src/libudev/def.h index 3c44e27121..d4844f4186 100644 --- a/src/libudev/def.h +++ b/src/libudev/def.h @@ -24,3 +24,8 @@ #include "util.h" #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" + +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS diff --git a/src/libudev/hashmap.c b/src/libudev/hashmap.c index c483fbad11..23e42f7b34 100644 --- a/src/libudev/hashmap.c +++ b/src/libudev/hashmap.c @@ -27,8 +27,9 @@ #include "util.h" #include "hashmap.h" #include "macro.h" +#include "siphash24.h" -#define NBUCKETS 127 +#define INITIAL_N_BUCKETS 31 struct hashmap_entry { const void *key; @@ -42,12 +43,13 @@ struct Hashmap { compare_func_t compare_func; struct hashmap_entry *iterate_list_head, *iterate_list_tail; - unsigned n_entries; - bool from_pool; -}; + struct hashmap_entry ** buckets; + unsigned n_buckets, n_entries; -#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap)))) + uint8_t hash_key[HASH_KEY_SIZE]; + bool from_pool:1; +}; struct pool { struct pool *next; @@ -61,9 +63,15 @@ static void *first_hashmap_tile = NULL; static struct pool *first_entry_pool = NULL; static void *first_entry_tile = NULL; -static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size) { +static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size, unsigned at_least) { unsigned i; + /* When a tile is released we add it to the list and simply + * place the next pointer at its offset 0. */ + + assert(tile_size >= sizeof(void*)); + assert(at_least > 0); + if (*first_tile) { void *r; @@ -78,7 +86,7 @@ static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t t struct pool *p; n = *first_pool ? (*first_pool)->n_tiles : 0; - n = MAX(512U, n * 2); + n = MAX(at_least, n * 2); size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size); n = (size - ALIGN(sizeof(struct pool))) / tile_size; @@ -103,30 +111,49 @@ static void deallocate_tile(void **first_tile, void *p) { *first_tile = p; } -unsigned string_hash_func(const void *p) { - unsigned hash = 5381; - const signed char *c; - - /* DJB's hash function */ - - for (c = p; *c; c++) - hash = (hash << 5) + hash + (unsigned) *c; - - return hash; +unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, p, strlen(p), hash_key); + return (unsigned long) u; } int string_compare_func(const void *a, const void *b) { return strcmp(a, b); } -unsigned trivial_hash_func(const void *p) { - return PTR_TO_UINT(p); +unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); + return (unsigned long) u; } int trivial_compare_func(const void *a, const void *b) { return a < b ? -1 : (a > b ? 1 : 0); } +static unsigned bucket_hash(Hashmap *h, const void *p) { + return (unsigned) (h->hash_func(p, h->hash_key) % h->n_buckets); +} + +static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { + static uint8_t current[HASH_KEY_SIZE]; + static bool current_initialized = false; + + /* Returns a hash function key to use. In order to keep things + * fast we will not generate a new key each time we allocate a + * new hash table. Instead, we'll just reuse the most recently + * generated one, except if we never generated one or when we + * are rehashing an entire hash table because we reached a + * fill level */ + + if (!current_initialized || !reuse_is_ok) { + random_bytes(current, sizeof(current)); + current_initialized = true; + } + + memcpy(hash_key, current, sizeof(current)); +} + Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { bool b; Hashmap *h; @@ -134,10 +161,10 @@ Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { b = is_main_thread(); - size = ALIGN(sizeof(Hashmap)) + NBUCKETS * sizeof(struct hashmap_entry*); + size = ALIGN(sizeof(Hashmap)) + INITIAL_N_BUCKETS * sizeof(struct hashmap_entry*); if (b) { - h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size); + h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size, 8); if (!h) return NULL; @@ -152,11 +179,16 @@ Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { h->hash_func = hash_func ? hash_func : trivial_hash_func; h->compare_func = compare_func ? compare_func : trivial_compare_func; + h->n_buckets = INITIAL_N_BUCKETS; h->n_entries = 0; h->iterate_list_head = h->iterate_list_tail = NULL; + h->buckets = (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap))); + h->from_pool = b; + get_hash_key(h->hash_key, true); + return h; } @@ -165,11 +197,11 @@ static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { assert(e); /* Insert into hash table */ - e->bucket_next = BY_HASH(h)[hash]; + e->bucket_next = h->buckets[hash]; e->bucket_previous = NULL; - if (BY_HASH(h)[hash]) - BY_HASH(h)[hash]->bucket_previous = e; - BY_HASH(h)[hash] = e; + if (h->buckets[hash]) + h->buckets[hash]->bucket_previous = e; + h->buckets[hash] = e; /* Insert into iteration list */ e->iterate_previous = h->iterate_list_tail; @@ -209,7 +241,7 @@ static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { if (e->bucket_previous) e->bucket_previous->bucket_next = e->bucket_next; else - BY_HASH(h)[hash] = e->bucket_next; + h->buckets[hash] = e->bucket_next; assert(h->n_entries >= 1); h->n_entries--; @@ -221,8 +253,7 @@ static void remove_entry(Hashmap *h, struct hashmap_entry *e) { assert(h); assert(e); - hash = h->hash_func(e->key) % NBUCKETS; - + hash = bucket_hash(h, e->key); unlink_entry(h, e, hash); if (h->from_pool) @@ -240,6 +271,9 @@ void hashmap_free(Hashmap*h) { hashmap_clear(h); + if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap)))) + free(h->buckets); + if (h->from_pool) deallocate_tile(&first_hashmap_tile, h); else @@ -279,34 +313,92 @@ void hashmap_clear_free(Hashmap *h) { static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; assert(h); - assert(hash < NBUCKETS); + assert(hash < h->n_buckets); - for (e = BY_HASH(h)[hash]; e; e = e->bucket_next) + for (e = h->buckets[hash]; e; e = e->bucket_next) if (h->compare_func(e->key, key) == 0) return e; return NULL; } +static bool resize_buckets(Hashmap *h) { + struct hashmap_entry **n, *i; + unsigned m; + uint8_t nkey[HASH_KEY_SIZE]; + + assert(h); + + if (_likely_(h->n_entries*4 < h->n_buckets*3)) + return false; + + /* Increase by four */ + m = (h->n_entries+1)*4-1; + + /* If we hit OOM we simply risk packed hashmaps... */ + n = new0(struct hashmap_entry*, m); + if (!n) + return false; + + /* Let's use a different randomized hash key for the + * extension, so that people cannot guess what we are using + * here forever */ + get_hash_key(nkey, false); + + for (i = h->iterate_list_head; i; i = i->iterate_next) { + unsigned long old_bucket, new_bucket; + + old_bucket = h->hash_func(i->key, h->hash_key) % h->n_buckets; + + /* First, drop from old bucket table */ + if (i->bucket_next) + i->bucket_next->bucket_previous = i->bucket_previous; + + if (i->bucket_previous) + i->bucket_previous->bucket_next = i->bucket_next; + else + h->buckets[old_bucket] = i->bucket_next; + + /* Then, add to new backet table */ + new_bucket = h->hash_func(i->key, nkey) % m; + + i->bucket_next = n[new_bucket]; + i->bucket_previous = NULL; + if (n[new_bucket]) + n[new_bucket]->bucket_previous = i; + n[new_bucket] = i; + } + + if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap)))) + free(h->buckets); + + h->buckets = n; + h->n_buckets = m; + + memcpy(h->hash_key, nkey, HASH_KEY_SIZE); + + return true; +} + int hashmap_put(Hashmap *h, const void *key, void *value) { struct hashmap_entry *e; unsigned hash; assert(h); - hash = h->hash_func(key) % NBUCKETS; - + hash = bucket_hash(h, key); e = hash_scan(h, hash, key); if (e) { - if (e->value == value) return 0; - return -EEXIST; } + if (resize_buckets(h)) + hash = bucket_hash(h, key); + if (h->from_pool) - e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry)); + e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry), 64U); else e = new(struct hashmap_entry, 1); @@ -328,7 +420,7 @@ void* hashmap_get(Hashmap *h, const void *key) { if (!h) return NULL; - hash = h->hash_func(key) % NBUCKETS; + hash = bucket_hash(h, key); e = hash_scan(h, hash, key); if (!e) return NULL; @@ -342,12 +434,8 @@ bool hashmap_contains(Hashmap *h, const void *key) { if (!h) return false; - hash = h->hash_func(key) % NBUCKETS; - - if (!hash_scan(h, hash, key)) - return false; - - return true; + hash = bucket_hash(h, key); + return !!hash_scan(h, hash, key); } void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { diff --git a/src/libudev/hashmap.h b/src/libudev/hashmap.h index 3b65142eca..387c32243e 100644 --- a/src/libudev/hashmap.h +++ b/src/libudev/hashmap.h @@ -30,6 +30,8 @@ * for all read operations. That way it is not necessary to * instantiate an object for each Hashmap use. */ +#define HASH_KEY_SIZE 16 + typedef struct Hashmap Hashmap; typedef struct _IteratorStruct _IteratorStruct; typedef _IteratorStruct* Iterator; @@ -37,16 +39,16 @@ typedef _IteratorStruct* Iterator; #define ITERATOR_FIRST ((Iterator) 0) #define ITERATOR_LAST ((Iterator) -1) -typedef unsigned (*hash_func_t)(const void *p); +typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); typedef int (*compare_func_t)(const void *a, const void *b); -unsigned string_hash_func(const void *p) _pure_; +unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int string_compare_func(const void *a, const void *b) _pure_; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ -unsigned trivial_hash_func(const void *p) _const_; +unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int trivial_compare_func(const void *a, const void *b) _const_; Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func); diff --git a/src/libudev/libudev-queue-private.c b/src/libudev/libudev-queue-private.c index 51a1d672be..80d7ceef2b 100644 --- a/src/libudev/libudev-queue-private.c +++ b/src/libudev/libudev-queue-private.c @@ -224,8 +224,8 @@ static int rebuild_queue_file(struct udev_queue_export *udev_queue_export) if (new_queue_file == NULL) goto error; seqnum = udev_queue_export->seqnum_max; - if (fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file) != sizeof(unsigned long long int)) - goto error; + fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file); + /* copy unfinished events only to the new file */ if (devpaths != NULL) { for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) { @@ -239,12 +239,9 @@ static int rebuild_queue_file(struct udev_queue_export *udev_queue_export) err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath)); devpath_len = err; - if (fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file) != 1) - goto error; - if (fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file) != 1) - goto error; - if (fwrite(devpath, 1, devpath_len, new_queue_file) != devpath_len) - goto error; + fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file); + fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file); + fwrite(devpath, 1, devpath_len, new_queue_file); } seqnum++; } diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index 2c31d5b1db..6087c8f106 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -87,11 +87,8 @@ uid_t util_lookup_user(struct udev *udev, const char *user) struct passwd *pw; uid_t uid; size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); - char *buf; + char *buf = alloca(buflen); - if (buflen == -1) - buflen = 1024; - buf = alloca(buflen); if (streq(user, "root")) return 0; uid = strtoul(user, &endptr, 10); @@ -114,11 +111,9 @@ gid_t util_lookup_group(struct udev *udev, const char *group) struct group grbuf; struct group *gr; gid_t gid = 0; - size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *buf = NULL; - if (buflen == -1) - buflen = 1024; if (streq(group, "root")) return 0; gid = strtoul(group, &endptr, 10); diff --git a/src/libudev/log.c b/src/libudev/log.c index da5ad583d9..75157083c6 100644 --- a/src/libudev/log.c +++ b/src/libudev/log.c @@ -115,10 +115,7 @@ void log_close_syslog(void) { static int create_log_socket(int type) { int fd; - /* All output to the syslog/journal fds we do asynchronously, - * and if the buffers are full we just drop the messages */ - - fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0); if (fd < 0) return -errno; @@ -190,6 +187,12 @@ int log_open(void) { getpid() == 1 || isatty(STDERR_FILENO) <= 0) { + if (log_target == LOG_TARGET_AUTO) + if (r >= 0) { + log_close_syslog(); + log_close_console(); + return r; + } if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || log_target == LOG_TARGET_SYSLOG) { r = log_open_syslog(); @@ -214,8 +217,6 @@ int log_open(void) { log_close_syslog(); - /* Get the real /dev/console if we are PID=1, hence reopen */ - log_close_console(); return log_open_console(); } @@ -270,8 +271,25 @@ static int write_to_console( IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); IOVEC_SET_STRING(iovec[n++], "\n"); - if (writev(console_fd, iovec, n) < 0) - return -errno; + if (writev(console_fd, iovec, n) < 0) { + + if (errno == EIO && getpid() == 1) { + + /* If somebody tried to kick us from our + * console tty (via vhangup() or suchlike), + * try to reconnect */ + + log_close_console(); + log_open_console(); + + if (console_fd < 0) + return 0; + + if (writev(console_fd, iovec, n) < 0) + return -errno; + } else + return -errno; + } return 1; } @@ -515,25 +533,29 @@ int log_meta( #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" -_noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) { +static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) { static char buffer[LINE_MAX]; + if (_likely_(LOG_PRI(level) > log_max_level)) + return; + snprintf(buffer, sizeof(buffer), format, text, file, line, func); char_array_0(buffer); log_abort_msg = buffer; - log_dispatch(LOG_CRIT, file, line, func, NULL, NULL, buffer); - abort(); + log_dispatch(level, file, line, func, NULL, NULL, buffer); } #pragma GCC diagnostic pop -_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) { - log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); +noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) { + log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); + abort(); } -_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { - log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); +noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { + log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); + abort(); } int log_oom_internal(const char *file, int line, const char *func) { @@ -541,6 +563,9 @@ int log_oom_internal(const char *file, int line, const char *func) { return -ENOMEM; } +int log_get_max_level(void) { + return log_max_level; +} static const char *const log_target_table[] = { [LOG_TARGET_CONSOLE] = "console", [LOG_TARGET_KMSG] = "kmsg", diff --git a/src/libudev/log.h b/src/libudev/log.h index 23ada2255c..45a4f9c2f0 100644 --- a/src/libudev/log.h +++ b/src/libudev/log.h @@ -44,6 +44,7 @@ typedef enum LogTarget{ void log_set_target(LogTarget target); void log_set_max_level(int level); +int log_get_max_level(void) _pure_; int log_open(void); void log_close(void); @@ -73,25 +74,32 @@ int log_oom_internal( int line, const char *func); -_noreturn_ void log_assert_failed( +noreturn void log_assert_failed( const char *text, const char *file, int line, const char *func); -_noreturn_ void log_assert_failed_unreachable( +noreturn void log_assert_failed_unreachable( const char *text, const char *file, int line, const char *func); -#define log_full(level, ...) log_meta(level, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_debug(...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_info(...) log_meta(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_notice(...) log_meta(LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_error(...) log_meta(LOG_ERR, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_full(level, ...) \ +do { \ + if (log_get_max_level() >= (level)) \ + log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__); \ +} while (0) + +#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) +#define log_info(...) log_full(LOG_INFO, __VA_ARGS__) +#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) +#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) +#define log_error(...) log_full(LOG_ERR, __VA_ARGS__) + +#define log_struct(level, ...) log_struct_internal(level, __FILE__, __LINE__, __func__, __VA_ARGS__) #define log_oom() log_oom_internal(__FILE__, __LINE__, __func__) diff --git a/src/libudev/macro.h b/src/libudev/macro.h index dddc040cec..835610caf3 100644 --- a/src/libudev/macro.h +++ b/src/libudev/macro.h @@ -30,7 +30,6 @@ #define _printf_(a,b) __attribute__ ((format (printf, a, b))) #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) #define _sentinel_ __attribute__ ((sentinel)) -#define _noreturn_ __attribute__((noreturn)) #define _pure_ __attribute__ ((pure)) #define _const_ __attribute__ ((const)) #define _packed_ __attribute__ ((packed)) @@ -68,7 +67,6 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { * @member: the name of the member within the struct. * */ - #define container_of(ptr, type, member) \ __extension__ ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ @@ -95,19 +93,9 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { } while (false) #if defined(static_assert) -#define assert_cc(expr) \ - do { \ - static_assert(expr, #expr); \ - } while (false) +#define assert_cc(expr) static_assert(expr, #expr) #else -#define assert_cc(expr) \ - do { \ - switch (0) { \ - case 0: \ - case !!(expr): \ - ; \ - } \ - } while (false) +#define assert_cc(expr) struct UNIQUE(_assert_struct_) { char x[(expr) ? 0 : -1]; }; #endif #define PTR_TO_INT(p) ((int) ((intptr_t) (p))) @@ -174,17 +162,39 @@ static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { * the const magic to the type, otherwise the compiler warns about * signed/unsigned comparison, because the magic can be 32 bit unsigned. */ -#define F_TYPE_CMP(a, b) (a == (typeof(a)) b) - +#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) /* Returns the number of chars needed to format variables of the * specified type as a decimal string. Adds in extra space for a * negative '-' prefix. */ - #define DECIMAL_STR_MAX(type) \ - (1+(sizeof(type) <= 1 ? 3 : \ + (2+(sizeof(type) <= 1 ? 3 : \ sizeof(type) <= 2 ? 5 : \ sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) +/* Define C11 thread_local attribute even on older gcc compiler + * version */ +#ifndef thread_local +/* + * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + */ +#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +#define thread_local _Thread_local +#else +#define thread_local __thread +#endif +#endif + +/* Define C11 noreturn without and even on older gcc + * compiler versions */ +#ifndef noreturn +#if __STDC_VERSION__ >= 201112L +#define noreturn _Noreturn +#else +#define noreturn __attribute__((noreturn)) +#endif +#endif + #include "log.h" diff --git a/src/libudev/path-util.c b/src/libudev/path-util.c index 616577088c..a4484c8de1 100644 --- a/src/libudev/path-util.c +++ b/src/libudev/path-util.c @@ -107,7 +107,7 @@ char *path_make_absolute(const char *p, const char *prefix) { } char *path_make_absolute_cwd(const char *p) { - char *cwd, *r; + _cleanup_free_ char *cwd = NULL; assert(p); @@ -121,10 +121,7 @@ char *path_make_absolute_cwd(const char *p) { if (!cwd) return NULL; - r = path_make_absolute(p, cwd); - free(cwd); - - return r; + return path_make_absolute(p, cwd); } char **path_strv_canonicalize(char **l) { @@ -152,7 +149,7 @@ char **path_strv_canonicalize(char **l) { } errno = 0; - u = realpath(t, 0); + u = canonicalize_file_name(t); if (!u) { if (errno == ENOENT) u = t; @@ -332,33 +329,37 @@ fallback: return a.st_dev != b.st_dev; } -bool paths_check_timestamp(char **paths, usec_t *paths_ts_usec, bool update) -{ - unsigned int i; +bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { bool changed = false; + const char* const* i; + + assert(timestamp); if (paths == NULL) - goto out; + return false; - for (i = 0; paths[i]; i++) { + STRV_FOREACH(i, paths) { struct stat stats; + usec_t u; - if (stat(paths[i], &stats) < 0) + if (stat(*i, &stats) < 0) continue; - if (paths_ts_usec[i] == timespec_load(&stats.st_mtim)) - continue; + u = timespec_load(&stats.st_mtim); /* first check */ - if (paths_ts_usec[i] != 0) { - log_debug("reload - timestamp of '%s' changed\n", paths[i]); - changed = true; - } + if (*timestamp >= u) + continue; + + log_debug("timestamp of '%s' changed", *i); /* update timestamp */ - if (update) - paths_ts_usec[i] = timespec_load(&stats.st_mtim); + if (update) { + *timestamp = u; + changed = true; + } else + return true; } -out: + return changed; } diff --git a/src/libudev/path-util.h b/src/libudev/path-util.h index 0b7577ff4f..eea7589d00 100644 --- a/src/libudev/path-util.h +++ b/src/libudev/path-util.h @@ -35,5 +35,5 @@ char** path_strv_canonicalize(char **l); char** path_strv_canonicalize_uniq(char **l); int path_is_mount_point(const char *path, bool allow_symlink); +bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); -bool paths_check_timestamp(char **paths, usec_t *paths_ts_usec, bool update); diff --git a/src/libudev/siphash24.c b/src/libudev/siphash24.c new file mode 100644 index 0000000000..f68bd283a1 --- /dev/null +++ b/src/libudev/siphash24.c @@ -0,0 +1,135 @@ +/* + SipHash reference C implementation + + Written in 2012 by + Jean-Philippe Aumasson + Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . + + (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) +*/ +#include +#include +#include + +#include "siphash24.h" + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint8_t u8; + +#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) ) + +#define U32TO8_LE(p, v) \ + (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \ + (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (u32)((v) )); \ + U32TO8_LE((p) + 4, (u32)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((u64)((p)[0]) ) | \ + ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | \ + ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | \ + ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \ + v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \ + v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \ + v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \ + } while(0) + +/* SipHash-2-4 */ +void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) +{ + /* "somepseudorandomlygeneratedbytes" */ + u64 v0 = 0x736f6d6570736575ULL; + u64 v1 = 0x646f72616e646f6dULL; + u64 v2 = 0x6c7967656e657261ULL; + u64 v3 = 0x7465646279746573ULL; + u64 b; + u64 k0 = U8TO64_LE( k ); + u64 k1 = U8TO64_LE( k + 8 ); + u64 m; + const u8 *in = _in; + const u8 *end = in + inlen - ( inlen % sizeof( u64 ) ); + const int left = inlen & 7; + b = ( ( u64 )inlen ) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + for ( ; in != end; in += 8 ) + { + m = U8TO64_LE( in ); +#ifdef DEBUG + printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); + printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); + printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); + printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m ); +#endif + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } + + switch( left ) + { + case 7: b |= ( ( u64 )in[ 6] ) << 48; + + case 6: b |= ( ( u64 )in[ 5] ) << 40; + + case 5: b |= ( ( u64 )in[ 4] ) << 32; + + case 4: b |= ( ( u64 )in[ 3] ) << 24; + + case 3: b |= ( ( u64 )in[ 2] ) << 16; + + case 2: b |= ( ( u64 )in[ 1] ) << 8; + + case 1: b |= ( ( u64 )in[ 0] ); break; + + case 0: break; + } + +#ifdef DEBUG + printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); + printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); + printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); + printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b ); +#endif + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; +#ifdef DEBUG + printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); + printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); + printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); + printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); +#endif + v2 ^= 0xff; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE( out, b ); +} diff --git a/src/libudev/siphash24.h b/src/libudev/siphash24.h new file mode 100644 index 0000000000..3253c179b6 --- /dev/null +++ b/src/libudev/siphash24.h @@ -0,0 +1,4 @@ +#include +#include + +void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/libudev/socket-util.h b/src/libudev/socket-util.h index f362757bc0..2daa3279fa 100644 --- a/src/libudev/socket-util.h +++ b/src/libudev/socket-util.h @@ -1,9 +1,5 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - /*** - This file is part of systemd. + This file is part of eudev, forked from systemd. Copyright 2010 Lennart Poettering @@ -21,14 +17,20 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include +#include #include +#include union sockaddr_union { struct sockaddr sa; - struct sockaddr_in in4; + struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr_un un; struct sockaddr_nl nl; struct sockaddr_storage storage; + struct sockaddr_ll ll; }; diff --git a/src/libudev/sparse-endian.h b/src/libudev/sparse-endian.h index 51694bebb7..eb4dbf3615 100644 --- a/src/libudev/sparse-endian.h +++ b/src/libudev/sparse-endian.h @@ -23,7 +23,6 @@ #include #include -#include #ifdef __CHECKER__ #define __bitwise __attribute__((bitwise)) diff --git a/src/libudev/strv.c b/src/libudev/strv.c index 3619701e9d..cbfe2388d6 100644 --- a/src/libudev/strv.c +++ b/src/libudev/strv.c @@ -202,15 +202,11 @@ char **strv_remove(char **l, const char *s) { /* Drops every occurrence of s in the string list, edits * in-place. */ - for (f = t = l; *f; f++) { - - if (streq(*f, s)) { + for (f = t = l; *f; f++) + if (streq(*f, s)) free(*f); - continue; - } - - *(t++) = *f; - } + else + *(t++) = *f; *t = NULL; return l; diff --git a/src/libudev/strv.h b/src/libudev/strv.h index 9fba94e566..12fa9f0524 100644 --- a/src/libudev/strv.h +++ b/src/libudev/strv.h @@ -31,6 +31,7 @@ static inline void strv_freep(char ***l) { strv_free(*l); } +void strv_free(char **l); #define _cleanup_strv_free_ _cleanup_(strv_freep) char **strv_copy(char * const *l); diff --git a/src/libudev/strxcpyx.c b/src/libudev/strxcpyx.c index fbdf5ac658..6efa237d4b 100644 --- a/src/libudev/strxcpyx.c +++ b/src/libudev/strxcpyx.c @@ -29,8 +29,7 @@ #include #include "strxcpyx.h" -size_t strpcpy(char **dest, size_t size, const char *src) -{ +size_t strpcpy(char **dest, size_t size, const char *src) { size_t len; len = strlen(src); @@ -48,8 +47,7 @@ size_t strpcpy(char **dest, size_t size, const char *src) return size; } -size_t strpcpyf(char **dest, size_t size, const char *src, ...) -{ +size_t strpcpyf(char **dest, size_t size, const char *src, ...) { va_list va; int i; @@ -67,8 +65,7 @@ size_t strpcpyf(char **dest, size_t size, const char *src, ...) return size; } -size_t strpcpyl(char **dest, size_t size, const char *src, ...) -{ +size_t strpcpyl(char **dest, size_t size, const char *src, ...) { va_list va; va_start(va, src); @@ -80,8 +77,7 @@ size_t strpcpyl(char **dest, size_t size, const char *src, ...) return size; } -size_t strscpy(char *dest, size_t size, const char *src) -{ +size_t strscpy(char *dest, size_t size, const char *src) { char *s; s = dest; diff --git a/src/libudev/util.c b/src/libudev/util.c index 98be5307f6..93f60b8ec4 100644 --- a/src/libudev/util.c +++ b/src/libudev/util.c @@ -1,7 +1,5 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** - This file is part of systemd. + This file is part of eudev, forked from systemd. Copyright 2010 Lennart Poettering @@ -78,7 +76,7 @@ static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; size_t page_size(void) { - static __thread size_t pgsz = 0; + static thread_local size_t pgsz = 0; long r; if (_likely_(pgsz > 0)) @@ -615,6 +613,50 @@ bool ignore_file(const char *filename) { return ignore_file_allow_backup(filename); } +void random_bytes(void *p, size_t n) { + static bool srand_called = false; + _cleanup_close_ int fd; + ssize_t k; + uint8_t *q; + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + goto fallback; + + k = loop_read(fd, p, n, true); + if (k < 0 || (size_t) k != n) + goto fallback; + + return; + +fallback: + + if (!srand_called) { + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in + * auxv, so let's try to make use of that to seed the + * pseudo-random generator. It's better than + * nothing... */ + + void *auxv; + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + srand(*(unsigned*) auxv); + else +#endif + srand(time(NULL) + gettid()); + + srand_called = true; + } + + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ + for (q = p; q < (uint8_t*) p + n; q ++) + *q = rand(); +} + int open_terminal(const char *name, int mode) { int fd, r; unsigned c = 0; @@ -665,9 +707,9 @@ int open_terminal(const char *name, int mode) { _pure_ static int is_temporary_fs(struct statfs *s) { assert(s); - return - F_TYPE_CMP(s->f_type, TMPFS_MAGIC) || - F_TYPE_CMP(s->f_type, RAMFS_MAGIC); + + return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) || + F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC); } int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { @@ -823,6 +865,55 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { return 0; } +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { + uint8_t *p; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + p = buf; + + while (nbytes > 0) { + ssize_t k; + + if ((k = read(fd, p, nbytes)) <= 0) { + + if (k < 0 && errno == EINTR) + continue; + + if (k < 0 && errno == EAGAIN && do_poll) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + + if (poll(&pollfd, 1, -1) < 0) { + if (errno == EINTR) + continue; + + return n > 0 ? n : -errno; + } + + /* We knowingly ignore the revents value here, + * and expect that any error/EOF is reported + * via read()/write() + */ + + continue; + } + + return n > 0 ? n : (k < 0 ? -errno : 0); + } + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + char *strjoin(const char *x, ...) { va_list ap; size_t l; diff --git a/src/libudev/util.h b/src/libudev/util.h index 50e6a44af5..14233c9d7e 100644 --- a/src/libudev/util.h +++ b/src/libudev/util.h @@ -1,9 +1,5 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - /*** - This file is part of systemd. + This file is part of eudev, forked from systemd. Copyright 2010 Lennart Poettering @@ -21,6 +17,8 @@ along with systemd; If not, see . ***/ +#pragma once + #include #include #include @@ -149,6 +147,8 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pu bool ignore_file(const char *filename) _pure_; +void random_bytes(void *p, size_t n); + /* For basic lookup tables with strictly enumerated entries */ #define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ scope const char *name##_to_string(type i) { \ @@ -207,6 +207,7 @@ int open_terminal(const char *name, int mode); int fopen_temporary(const char *path, FILE **_f, char **_temp_path); +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); bool null_or_empty(struct stat *st) _pure_; -- cgit v1.2.3-54-g00ecf