diff options
author | Lucas De Marchi <lucas.demarchi@intel.com> | 2014-10-03 00:01:35 -0300 |
---|---|---|
committer | Lucas De Marchi <lucas.demarchi@intel.com> | 2014-10-03 00:33:25 -0300 |
commit | 96573a02208abebe4a884c0bbd0d6ecde9047f37 (patch) | |
tree | 1435476e04e26e15bee1d7bd30af26a8c50a31ae /shared | |
parent | 8b7189bc25b7becb0e428a74528d8def08bd2f4a (diff) | |
download | kmod-96573a02208abebe4a884c0bbd0d6ecde9047f37.tar.gz kmod-96573a02208abebe4a884c0bbd0d6ecde9047f37.tar.bz2 kmod-96573a02208abebe4a884c0bbd0d6ecde9047f37.zip |
Move generic util functions to shared directory
Diffstat (limited to 'shared')
-rw-r--r-- | shared/.gitignore | 5 | ||||
-rw-r--r-- | shared/util.c | 345 | ||||
-rw-r--r-- | shared/util.h | 64 |
3 files changed, 414 insertions, 0 deletions
diff --git a/shared/.gitignore b/shared/.gitignore new file mode 100644 index 0000000..088ef79 --- /dev/null +++ b/shared/.gitignore @@ -0,0 +1,5 @@ +.dirstamp +.deps/ +.libs/ +*.la +*.lo diff --git a/shared/util.c b/shared/util.c new file mode 100644 index 0000000..2d44107 --- /dev/null +++ b/shared/util.c @@ -0,0 +1,345 @@ +/* + * kmod - interface to kernel module operations + * + * Copyright (C) 2011-2013 ProFUSION embedded systems + * Copyright (C) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com> + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * 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 library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> + +#include <shared/util.h> + +#define USEC_PER_SEC 1000000ULL +#define NSEC_PER_USEC 1000ULL + +/* string handling functions and memory allocations */ +/* ************************************************************************ */ + +void *memdup(const void *p, size_t n) +{ + void *r = malloc(n); + + if (r == NULL) + return NULL; + + return memcpy(r, p, n); +} + +char *strchr_replace(char *s, int c, char r) +{ + char *p; + + for (p = s; *p != '\0'; p++) { + if (*p == c) + *p = r; + } + + return s; +} + +/* read-like and fread-like functions */ +/* ************************************************************************ */ +ssize_t read_str_safe(int fd, char *buf, size_t buflen) +{ + size_t todo = buflen - 1; + size_t done = 0; + + do { + ssize_t r = read(fd, buf + done, todo); + + if (r == 0) + break; + else if (r > 0) { + todo -= r; + done += r; + } else { + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINTR) + continue; + else + return -errno; + } + } while (todo > 0); + + buf[done] = '\0'; + return done; +} + +ssize_t write_str_safe(int fd, const char *buf, size_t buflen) +{ + size_t todo = buflen; + size_t done = 0; + + do { + ssize_t r = write(fd, buf + done, todo); + + if (r == 0) + break; + else if (r > 0) { + todo -= r; + done += r; + } else { + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINTR) + continue; + else + return -errno; + } + } while (todo > 0); + + return done; +} + +int read_str_long(int fd, long *value, int base) +{ + char buf[32], *end; + long v; + int err; + + *value = 0; + err = read_str_safe(fd, buf, sizeof(buf)); + if (err < 0) + return err; + errno = 0; + v = strtol(buf, &end, base); + if (end == buf || !isspace(*end)) + return -EINVAL; + + *value = v; + return 0; +} + +int read_str_ulong(int fd, unsigned long *value, int base) +{ + char buf[32], *end; + long v; + int err; + + *value = 0; + err = read_str_safe(fd, buf, sizeof(buf)); + if (err < 0) + return err; + errno = 0; + v = strtoul(buf, &end, base); + if (end == buf || !isspace(*end)) + return -EINVAL; + *value = v; + return 0; +} + +/* + * Read one logical line from a configuration file. + * + * Line endings may be escaped with backslashes, to form one logical line from + * several physical lines. No end of line character(s) are included in the + * result. + * + * If linenum is not NULL, it is incremented by the number of physical lines + * which have been read. + */ +char *getline_wrapped(FILE *fp, unsigned int *linenum) +{ + int size = 256; + int i = 0, n = 0; + _cleanup_free_ char *buf = malloc(size); + + if (buf == NULL) + return NULL; + + for(;;) { + int ch = getc_unlocked(fp); + + switch(ch) { + case EOF: + if (i == 0) + return NULL; + /* else fall through */ + + case '\n': + n++; + + { + char *ret; + if (i == size) { + ret = realloc(buf, size + 1); + if (!ret) + return NULL; + } else + ret = buf; + ret[i] = '\0'; + buf = NULL; + if (linenum) + *linenum += n; + return ret; + } + + case '\\': + ch = getc_unlocked(fp); + + if (ch == '\n') { + n++; + continue; + } + /* else fall through */ + + default: + buf[i++] = ch; + + if (i == size) { + char *tmp; + size *= 2; + tmp = realloc(buf, size); + if (!tmp) + return NULL; + buf = tmp; + } + } + } +} + +/* path handling functions */ +/* ************************************************************************ */ + +bool path_is_absolute(const char *p) +{ + assert(p != NULL); + + return p[0] == '/'; +} + +char *path_make_absolute_cwd(const char *p) +{ + _cleanup_free_ char *cwd = NULL; + size_t plen, cwdlen; + char *r; + + if (path_is_absolute(p)) + return strdup(p); + + cwd = get_current_dir_name(); + if (!cwd) + return NULL; + + plen = strlen(p); + cwdlen = strlen(cwd); + + /* cwd + '/' + p + '\0' */ + r = realloc(cwd, cwdlen + 1 + plen + 1); + if (r == NULL) + return NULL; + + cwd = NULL; + r[cwdlen] = '/'; + memcpy(&r[cwdlen + 1], p, plen + 1); + + return r; +} + +static inline int is_dir(const char *path) +{ + struct stat st; + + if (stat(path, &st) >= 0) + return S_ISDIR(st.st_mode); + + return -errno; +} + +int mkdir_p(const char *path, int len, mode_t mode) +{ + char *start, *end; + + start = strndupa(path, len); + end = start + len; + + /* + * scan backwards, replacing '/' with '\0' while the component doesn't + * exist + */ + for (;;) { + int r = is_dir(start); + if (r > 0) { + end += strlen(end); + + if (end == start + len) + return 0; + + /* end != start, since it would be caught on the first + * iteration */ + *end = '/'; + break; + } else if (r == 0) + return -ENOTDIR; + + if (end == start) + break; + + *end = '\0'; + + /* Find the next component, backwards, discarding extra '/'*/ + while (end > start && *end != '/') + end--; + + while (end > start && *(end - 1) == '/') + end--; + } + + for (; end < start + len;) { + if (mkdir(start, mode) < 0 && errno != EEXIST) + return -errno; + + end += strlen(end); + *end = '/'; + } + + return 0; +} + +int mkdir_parents(const char *path, mode_t mode) +{ + char *end = strrchr(path, '/'); + + /* no parent directories */ + if (end == NULL) + return 0; + + return mkdir_p(path, end - path, mode); +} + +unsigned long long ts_usec(const struct timespec *ts) +{ + return (unsigned long long) ts->tv_sec * USEC_PER_SEC + + (unsigned long long) ts->tv_nsec / NSEC_PER_USEC; +} + +unsigned long long stat_mstamp(const struct stat *st) +{ +#ifdef HAVE_STRUCT_STAT_ST_MTIM + return ts_usec(&st->st_mtim); +#else + return (unsigned long long) st->st_mtime; +#endif +} diff --git a/shared/util.h b/shared/util.h new file mode 100644 index 0000000..1ed7214 --- /dev/null +++ b/shared/util.h @@ -0,0 +1,64 @@ +#pragma once + +#include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <shared/macro.h> + +/* string handling functions and memory allocations */ +/* ************************************************************************ */ +#define streq(a, b) (strcmp((a), (b)) == 0) +#define strstartswith(a, b) (strncmp(a, b, strlen(b)) == 0) +char *strchr_replace(char *s, int c, char r); +void *memdup(const void *p, size_t n) __attribute__((nonnull(1))); + +/* read-like and fread-like functions */ +/* ************************************************************************ */ +ssize_t read_str_safe(int fd, char *buf, size_t buflen) _must_check_ __attribute__((nonnull(2))); +ssize_t write_str_safe(int fd, const char *buf, size_t buflen) __attribute__((nonnull(2))); +int read_str_long(int fd, long *value, int base) _must_check_ __attribute__((nonnull(2))); +int read_str_ulong(int fd, unsigned long *value, int base) _must_check_ __attribute__((nonnull(2))); +char *getline_wrapped(FILE *fp, unsigned int *linenum) __attribute__((nonnull(1))); + +/* path handling functions */ +/* ************************************************************************ */ +bool path_is_absolute(const char *p) _must_check_ __attribute__((nonnull(1))); +char *path_make_absolute_cwd(const char *p) _must_check_ __attribute__((nonnull(1))); +int mkdir_p(const char *path, int len, mode_t mode); +int mkdir_parents(const char *path, mode_t mode); +unsigned long long stat_mstamp(const struct stat *st); +unsigned long long ts_usec(const struct timespec *ts); + +/* endianess and alignments */ +/* ************************************************************************ */ +#define get_unaligned(ptr) \ +({ \ + struct __attribute__((packed)) { \ + typeof(*(ptr)) __v; \ + } *__p = (typeof(__p)) (ptr); \ + __p->__v; \ +}) + +#define put_unaligned(val, ptr) \ +do { \ + struct __attribute__((packed)) { \ + typeof(*(ptr)) __v; \ + } *__p = (typeof(__p)) (ptr); \ + __p->__v = (val); \ +} while(0) + +static _always_inline_ unsigned int ALIGN_POWER2(unsigned int u) +{ + return 1 << ((sizeof(u) * 8) - __builtin_clz(u - 1)); +} + +/* misc */ +/* ************************************************************************ */ +static inline void freep(void *p) { + free(*(void**) p); +} +#define _cleanup_free_ _cleanup_(freep) |