From b1ac60946d1625e14029ea9b7fa3aa4c06e0795f Mon Sep 17 00:00:00 2001 From: "Anthony G. Basile" Date: Tue, 5 Aug 2014 19:22:24 -0400 Subject: src/shared: refactor shared code Signed-off-by: Anthony G. Basile --- .gitignore | 20 +- configure.ac | 1 + src/Makefile.am | 1 + src/accelerometer/Makefile.am | 4 +- src/ata_id/Makefile.am | 4 +- src/cdrom_id/Makefile.am | 4 +- src/collect/Makefile.am | 4 +- src/libudev/Makefile.am | 54 +- src/libudev/MurmurHash2.c | 86 --- src/libudev/MurmurHash2.h | 33 -- src/libudev/cgroup-util.c | 252 --------- src/libudev/cgroup-util.h | 53 -- src/libudev/conf-files.c | 148 ----- src/libudev/conf-files.h | 28 - src/libudev/def.h | 31 -- src/libudev/device-nodes.c | 75 --- src/libudev/device-nodes.h | 23 - src/libudev/exit-status.c | 48 -- src/libudev/exit-status.h | 31 -- src/libudev/fileio.c | 143 ----- src/libudev/fileio.h | 27 - src/libudev/hashmap.c | 550 ------------------- src/libudev/hashmap.h | 75 --- src/libudev/ioprio.h | 20 - src/libudev/log.c | 579 -------------------- src/libudev/log.h | 107 ---- src/libudev/macro.h | 201 ------- src/libudev/missing.h | 114 ---- src/libudev/path-util.c | 364 ------------- src/libudev/path-util.h | 37 -- src/libudev/set.c | 58 -- src/libudev/set.h | 47 -- src/libudev/siphash24.c | 135 ----- src/libudev/siphash24.h | 4 - src/libudev/socket-util.h | 36 -- src/libudev/sparse-endian.h | 88 --- src/libudev/strbuf.c | 200 ------- src/libudev/strbuf.h | 56 -- src/libudev/strv.c | 218 -------- src/libudev/strv.h | 55 -- src/libudev/strxcpyx.c | 100 ---- src/libudev/strxcpyx.h | 33 -- src/libudev/time-util.c | 157 ------ src/libudev/time-util.h | 64 --- src/libudev/utf8.c | 249 --------- src/libudev/utf8.h | 31 -- src/libudev/util.c | 1187 ----------------------------------------- src/libudev/util.h | 353 ------------ src/scsi_id/Makefile.am | 4 +- src/shared/Makefile.am | 63 +++ src/shared/MurmurHash2.c | 86 +++ src/shared/MurmurHash2.h | 33 ++ src/shared/cgroup-util.c | 252 +++++++++ src/shared/cgroup-util.h | 53 ++ src/shared/conf-files.c | 148 +++++ src/shared/conf-files.h | 28 + src/shared/def.h | 31 ++ src/shared/dev-setup.c | 84 +++ src/shared/dev-setup.h | 24 + src/shared/device-nodes.c | 75 +++ src/shared/device-nodes.h | 23 + src/shared/exit-status.c | 48 ++ src/shared/exit-status.h | 31 ++ src/shared/fileio.c | 143 +++++ src/shared/fileio.h | 27 + src/shared/hashmap.c | 550 +++++++++++++++++++ src/shared/hashmap.h | 75 +++ src/shared/ioprio.h | 20 + src/shared/label.c | 247 +++++++++ src/shared/label.h | 38 ++ src/shared/log.c | 579 ++++++++++++++++++++ src/shared/log.h | 107 ++++ src/shared/macro.h | 201 +++++++ src/shared/missing.h | 114 ++++ src/shared/mkdir.c | 157 ++++++ src/shared/mkdir.h | 29 + src/shared/path-util.c | 364 +++++++++++++ src/shared/path-util.h | 37 ++ src/shared/set.c | 58 ++ src/shared/set.h | 47 ++ src/shared/siphash24.c | 135 +++++ src/shared/siphash24.h | 4 + src/shared/smack-util.c | 89 +++ src/shared/smack-util.h | 28 + src/shared/socket-util.h | 36 ++ src/shared/sparse-endian.h | 88 +++ src/shared/strbuf.c | 200 +++++++ src/shared/strbuf.h | 56 ++ src/shared/strv.c | 218 ++++++++ src/shared/strv.h | 55 ++ src/shared/strxcpyx.c | 100 ++++ src/shared/strxcpyx.h | 33 ++ src/shared/time-util.c | 157 ++++++ src/shared/time-util.h | 64 +++ src/shared/udev-util.h | 42 ++ src/shared/utf8.c | 249 +++++++++ src/shared/utf8.h | 31 ++ src/shared/util.c | 1187 +++++++++++++++++++++++++++++++++++++++++ src/shared/util.h | 353 ++++++++++++ src/udev/Makefile.am | 18 +- src/udev/dev-setup.c | 84 --- src/udev/dev-setup.h | 24 - src/udev/label.c | 247 --------- src/udev/label.h | 38 -- src/udev/mkdir.c | 157 ------ src/udev/mkdir.h | 29 - src/udev/smack-util.c | 89 --- src/udev/smack-util.h | 28 - src/udev/udev-util.h | 42 -- test/Makefile.am | 4 +- 110 files changed, 6940 insertions(+), 6909 deletions(-) delete mode 100644 src/libudev/MurmurHash2.c delete mode 100644 src/libudev/MurmurHash2.h delete mode 100644 src/libudev/cgroup-util.c delete mode 100644 src/libudev/cgroup-util.h delete mode 100644 src/libudev/conf-files.c delete mode 100644 src/libudev/conf-files.h delete mode 100644 src/libudev/def.h delete mode 100644 src/libudev/device-nodes.c delete mode 100644 src/libudev/device-nodes.h delete mode 100644 src/libudev/exit-status.c delete mode 100644 src/libudev/exit-status.h delete mode 100644 src/libudev/fileio.c delete mode 100644 src/libudev/fileio.h delete mode 100644 src/libudev/hashmap.c delete mode 100644 src/libudev/hashmap.h delete mode 100644 src/libudev/ioprio.h delete mode 100644 src/libudev/log.c delete mode 100644 src/libudev/log.h delete mode 100644 src/libudev/macro.h delete mode 100644 src/libudev/missing.h delete mode 100644 src/libudev/path-util.c delete mode 100644 src/libudev/path-util.h delete mode 100644 src/libudev/set.c delete mode 100644 src/libudev/set.h delete mode 100644 src/libudev/siphash24.c delete mode 100644 src/libudev/siphash24.h delete mode 100644 src/libudev/socket-util.h delete mode 100644 src/libudev/sparse-endian.h delete mode 100644 src/libudev/strbuf.c delete mode 100644 src/libudev/strbuf.h delete mode 100644 src/libudev/strv.c delete mode 100644 src/libudev/strv.h delete mode 100644 src/libudev/strxcpyx.c delete mode 100644 src/libudev/strxcpyx.h delete mode 100644 src/libudev/time-util.c delete mode 100644 src/libudev/time-util.h delete mode 100644 src/libudev/utf8.c delete mode 100644 src/libudev/utf8.h delete mode 100644 src/libudev/util.c delete mode 100644 src/libudev/util.h create mode 100644 src/shared/Makefile.am create mode 100644 src/shared/MurmurHash2.c create mode 100644 src/shared/MurmurHash2.h create mode 100644 src/shared/cgroup-util.c create mode 100644 src/shared/cgroup-util.h create mode 100644 src/shared/conf-files.c create mode 100644 src/shared/conf-files.h create mode 100644 src/shared/def.h create mode 100644 src/shared/dev-setup.c create mode 100644 src/shared/dev-setup.h create mode 100644 src/shared/device-nodes.c create mode 100644 src/shared/device-nodes.h create mode 100644 src/shared/exit-status.c create mode 100644 src/shared/exit-status.h create mode 100644 src/shared/fileio.c create mode 100644 src/shared/fileio.h create mode 100644 src/shared/hashmap.c create mode 100644 src/shared/hashmap.h create mode 100644 src/shared/ioprio.h create mode 100644 src/shared/label.c create mode 100644 src/shared/label.h create mode 100644 src/shared/log.c create mode 100644 src/shared/log.h create mode 100644 src/shared/macro.h create mode 100644 src/shared/missing.h create mode 100644 src/shared/mkdir.c create mode 100644 src/shared/mkdir.h create mode 100644 src/shared/path-util.c create mode 100644 src/shared/path-util.h create mode 100644 src/shared/set.c create mode 100644 src/shared/set.h create mode 100644 src/shared/siphash24.c create mode 100644 src/shared/siphash24.h create mode 100644 src/shared/smack-util.c create mode 100644 src/shared/smack-util.h create mode 100644 src/shared/socket-util.h create mode 100644 src/shared/sparse-endian.h create mode 100644 src/shared/strbuf.c create mode 100644 src/shared/strbuf.h create mode 100644 src/shared/strv.c create mode 100644 src/shared/strv.h create mode 100644 src/shared/strxcpyx.c create mode 100644 src/shared/strxcpyx.h create mode 100644 src/shared/time-util.c create mode 100644 src/shared/time-util.h create mode 100644 src/shared/udev-util.h create mode 100644 src/shared/utf8.c create mode 100644 src/shared/utf8.h create mode 100644 src/shared/util.c create mode 100644 src/shared/util.h delete mode 100644 src/udev/dev-setup.c delete mode 100644 src/udev/dev-setup.h delete mode 100644 src/udev/label.c delete mode 100644 src/udev/label.h delete mode 100644 src/udev/mkdir.c delete mode 100644 src/udev/mkdir.h delete mode 100644 src/udev/smack-util.c delete mode 100644 src/udev/smack-util.h delete mode 100644 src/udev/udev-util.h diff --git a/.gitignore b/.gitignore index 7fb273fb21..031b36aa4f 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,25 @@ m4/ltversion.m4 m4/lt~obsolete.m4 docs/gudev/version.xml +docs/gudev/*.txt +docs/gudev/*.stamp +docs/gudev/gudev.args +docs/gudev/gudev.hierarchy +docs/gudev/gudev.interfaces +docs/gudev/gudev.prerequisites +docs/gudev/gudev.signals +docs/gudev/html/ +docs/gudev/xml/ docs/libudev/version.xml -docs/gudev/gudev-overrides.txt -docs/libudev/libudev-overrides.txt +docs/libudev/*.txt +docs/libudev/*.stamp +docs/libudev/libudev.args +docs/libudev/libudev.hierarchy +docs/libudev/libudev.interfaces +docs/libudev/libudev.prerequisites +docs/libudev/libudev.signals +docs/libudev/html/ +docs/libudev/xml/ man/udev.7 man/udev.conf.5 man/udevd.8 diff --git a/configure.ac b/configure.ac index 6945976027..ca71aa9e1b 100644 --- a/configure.ac +++ b/configure.ac @@ -383,6 +383,7 @@ AC_CONFIG_FILES([Makefile src/v4l_id/Makefile src/gudev/Makefile src/gudev/gudev-1.0.pc + src/shared/Makefile src/libudev/Makefile src/libudev/libudev.pc src/udev/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index d6079f051b..41c66215e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = \ + shared \ libudev \ udev diff --git a/src/accelerometer/Makefile.am b/src/accelerometer/Makefile.am index 0afa86f2cb..983cf003d0 100644 --- a/src/accelerometer/Makefile.am +++ b/src/accelerometer/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ - -I $(top_srcdir)/src/libudev \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/libudev udevlibexec_PROGRAMS = \ accelerometer diff --git a/src/ata_id/Makefile.am b/src/ata_id/Makefile.am index d0c6a46e12..2dca2c1257 100644 --- a/src/ata_id/Makefile.am +++ b/src/ata_id/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ - -I $(top_srcdir)/src/libudev \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/libudev udevlibexec_PROGRAMS = \ ata_id diff --git a/src/cdrom_id/Makefile.am b/src/cdrom_id/Makefile.am index 9466bd84a3..488edcadb1 100644 --- a/src/cdrom_id/Makefile.am +++ b/src/cdrom_id/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ - -I $(top_srcdir)/src/libudev \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/libudev udevlibexec_PROGRAMS = \ cdrom_id diff --git a/src/collect/Makefile.am b/src/collect/Makefile.am index cdfe54d8a0..361a5a2094 100644 --- a/src/collect/Makefile.am +++ b/src/collect/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ - -I $(top_srcdir)/src/libudev \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/libudev udevlibexec_PROGRAMS = \ collect diff --git a/src/libudev/Makefile.am b/src/libudev/Makefile.am index e3971708fb..3b1b075a64 100644 --- a/src/libudev/Makefile.am +++ b/src/libudev/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} -LIBUDEV_CURRENT=2 -LIBUDEV_REVISION=6 -LIBUDEV_AGE=1 +LIBUDEV_CURRENT=6 +LIBUDEV_REVISION=0 +LIBUDEV_AGE=5 define move-to-rootlibdir if test "$(libdir)" != "$(rootlibdir)"; then \ @@ -19,7 +19,7 @@ AM_CPPFLAGS = \ -DUDEV_CONF_FILE=\"$(udevconffile)\" \ -DUDEV_HWDB_BIN=\"$(udevhwdbbin)\" \ -DUDEV_VERSION=$(UDEV_VERSION) \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared lib_LTLIBRARIES = \ libudev.la @@ -32,51 +32,11 @@ libudev_la_SOURCES =\ libudev-enumerate.c \ libudev-monitor.c \ libudev-queue.c \ - libudev-hwdb.c \ - cgroup-util.c \ - conf-files.c \ - device-nodes.c \ - exit-status.c \ - fileio.c \ - hashmap.c \ - log.c \ - MurmurHash2.c \ - path-util.c \ - set.c \ - siphash24.c \ - strbuf.c \ - strv.c \ - strxcpyx.c \ - time-util.c \ - util.c \ - utf8.c + libudev-hwdb.c noinst_HEADERS = \ libudev-hwdb-def.h \ - libudev-private.h \ - cgroup-util.h \ - conf-files.h \ - def.h \ - device-nodes.h \ - exit-status.h \ - fileio.h \ - hashmap.h \ - ioprio.h \ - log.h \ - macro.h \ - missing.h \ - MurmurHash2.h \ - path-util.h \ - set.h \ - siphash24.h \ - socket-util.h \ - sparse-endian.h \ - strbuf.h \ - strv.h \ - strxcpyx.h \ - time-util.h \ - util.h \ - utf8.h + libudev-private.h include_HEADERS = \ libudev.h @@ -86,6 +46,8 @@ libudev_la_LDFLAGS = \ -version-info $(LIBUDEV_CURRENT):$(LIBUDEV_REVISION):$(LIBUDEV_AGE) \ -Wl,--version-script=$(top_srcdir)/src/libudev/libudev.sym +libudev_la_LIBADD = \ + $(top_builddir)/src/shared/libudev_shared.la libudev_private_la_SOURCES =\ libudev-device-private.c diff --git a/src/libudev/MurmurHash2.c b/src/libudev/MurmurHash2.c deleted file mode 100644 index 2f4149dbe9..0000000000 --- a/src/libudev/MurmurHash2.c +++ /dev/null @@ -1,86 +0,0 @@ -//----------------------------------------------------------------------------- -// MurmurHash2 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. - -// Note - This code makes a few assumptions about how your machine behaves - - -// 1. We can read a 4-byte value from any address without crashing -// 2. sizeof(int) == 4 - -// And it has a few limitations - - -// 1. It will not work incrementally. -// 2. It will not produce the same results on little-endian and big-endian -// machines. - -#include "MurmurHash2.h" - -//----------------------------------------------------------------------------- -// Platform-specific functions and macros - -// Microsoft Visual Studio - -#if defined(_MSC_VER) - -#define BIG_CONSTANT(x) (x) - -// Other compilers - -#else // defined(_MSC_VER) - -#define BIG_CONSTANT(x) (x##LLU) - -#endif // !defined(_MSC_VER) - -//----------------------------------------------------------------------------- - -uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) -{ - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. - - const uint32_t m = 0x5bd1e995; - const int r = 24; - - // Initialize the hash to a 'random' value - - uint32_t h = seed ^ len; - - // Mix 4 bytes at a time into the hash - - const unsigned char * data = (const unsigned char *)key; - - while(len >= 4) - { - uint32_t k = *(uint32_t*)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; -} diff --git a/src/libudev/MurmurHash2.h b/src/libudev/MurmurHash2.h deleted file mode 100644 index 93362dd485..0000000000 --- a/src/libudev/MurmurHash2.h +++ /dev/null @@ -1,33 +0,0 @@ -//----------------------------------------------------------------------------- -// MurmurHash2 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. - -#ifndef _MURMURHASH2_H_ -#define _MURMURHASH2_H_ - -//----------------------------------------------------------------------------- -// Platform-specific functions and macros - -// Microsoft Visual Studio - -#if defined(_MSC_VER) - -typedef unsigned char uint8_t; -typedef unsigned long uint32_t; -typedef unsigned __int64 uint64_t; - -// Other compilers - -#else // defined(_MSC_VER) - -#include - -#endif // !defined(_MSC_VER) - -//----------------------------------------------------------------------------- - -uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ); - -//----------------------------------------------------------------------------- - -#endif // _MURMURHASH2_H_ diff --git a/src/libudev/cgroup-util.c b/src/libudev/cgroup-util.c deleted file mode 100644 index af6ce959c1..0000000000 --- a/src/libudev/cgroup-util.c +++ /dev/null @@ -1,252 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include - -#include "cgroup-util.h" -#include "set.h" -#include "path-util.h" - -int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { - _cleanup_free_ char *fs = NULL; - FILE *f; - int r; - - assert(_f); - - r = cg_get_path(controller, path, "cgroup.procs", &fs); - if (r < 0) - return r; - - f = fopen(fs, "re"); - if (!f) - return -errno; - - *_f = f; - return 0; -} - -int cg_read_pid(FILE *f, pid_t *_pid) { - unsigned long ul; - - /* Note that the cgroup.procs might contain duplicates! See - * cgroups.txt for details. */ - - assert(f); - assert(_pid); - - errno = 0; - if (fscanf(f, "%lu", &ul) != 1) { - - if (feof(f)) - return 0; - - return errno ? -errno : -EIO; - } - - if (ul <= 0) - return -EIO; - - *_pid = (pid_t) ul; - return 1; -} - -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) { - _cleanup_set_free_ Set *allocated_set = NULL; - bool done = false; - int r, ret = 0; - pid_t my_pid; - - assert(sig >= 0); - - /* This goes through the tasks list and kills them all. This - * is repeated until no further processes are added to the - * tasks list, to properly handle forking processes */ - - if (!s) { - s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); - if (!s) - return -ENOMEM; - } - - my_pid = getpid(); - - do { - _cleanup_fclose_ FILE *f = NULL; - pid_t pid = 0; - done = true; - - r = cg_enumerate_processes(controller, path, &f); - if (r < 0) { - if (ret >= 0 && r != -ENOENT) - return r; - - return ret; - } - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (ignore_self && pid == my_pid) - continue; - - if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) - continue; - - /* If we haven't killed this process yet, kill - * it */ - if (kill(pid, sig) < 0) { - if (ret >= 0 && errno != ESRCH) - ret = -errno; - } else if (ret == 0) { - - if (sigcont) - kill(pid, SIGCONT); - - ret = 1; - } - - done = false; - - r = set_put(s, LONG_TO_PTR(pid)); - if (r < 0) { - if (ret >= 0) - return r; - - return ret; - } - } - - if (r < 0) { - if (ret >= 0) - return r; - - return ret; - } - - /* To avoid racing against processes which fork - * quicker than we can kill them we repeat this until - * no new pids need to be killed. */ - - } while (!done); - - return ret; -} - -static const char *normalize_controller(const char *controller) { - - assert(controller); - - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) - return "systemd"; - else if (startswith(controller, "name=")) - return controller + 5; - else - return controller; -} - -static int join_path(const char *controller, const char *path, const char *suffix, char **fs) { - char *t = NULL; - - if (!isempty(controller)) { - if (!isempty(path) && !isempty(suffix)) - t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL); - else if (!isempty(path)) - t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL); - else if (!isempty(suffix)) - t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL); - else - t = strappend("/sys/fs/cgroup/", controller); - } else { - if (!isempty(path) && !isempty(suffix)) - t = strjoin(path, "/", suffix, NULL); - else if (!isempty(path)) - t = strdup(path); - else - return -EINVAL; - } - - if (!t) - return -ENOMEM; - - path_kill_slashes(t); - - *fs = t; - return 0; -} - -int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) { - const char *p; - static thread_local bool good = false; - - assert(fs); - - if (controller && !cg_controller_is_valid(controller, true)) - return -EINVAL; - - if (_unlikely_(!good)) { - int r; - - r = path_is_mount_point("/sys/fs/cgroup", false); - if (r <= 0) - return r < 0 ? r : -ENOENT; - - /* Cache this to save a few stat()s */ - good = true; - } - - p = controller ? normalize_controller(controller) : NULL; - - return join_path(p, path, suffix, fs); -} - - -#define CONTROLLER_VALID \ - DIGITS LETTERS \ - "_" - -bool cg_controller_is_valid(const char *p, bool allow_named) { - const char *t, *s; - - if (!p) - return false; - - if (allow_named) { - s = startswith(p, "name="); - if (s) - p = s; - } - - if (*p == 0 || *p == '_') - return false; - - for (t = p; *t; t++) - if (!strchr(CONTROLLER_VALID, *t)) - return false; - - if (t - p > FILENAME_MAX) - return false; - - return true; -} diff --git a/src/libudev/cgroup-util.h b/src/libudev/cgroup-util.h deleted file mode 100644 index 11e7308e19..0000000000 --- a/src/libudev/cgroup-util.h +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include - -#include "set.h" -#include "def.h" - -/* - * General rules: - * - * We accept named hierarchies in the syntax "foo" and "name=foo". - * - * We expect that named hierarchies do not conflict in name with a - * kernel hierarchy, modulo the "name=" prefix. - * - * We always generate "normalized" controller names, i.e. without the - * "name=" prefix. - * - * We require absolute cgroup paths. When returning, we will always - * generate paths with multiple adjacent / removed. - */ - -int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); -int cg_read_pid(FILE *f, pid_t *_pid); - -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s); - -int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs); - -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 deleted file mode 100644 index dc4f970313..0000000000 --- a/src/libudev/conf-files.c +++ /dev/null @@ -1,148 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" -#include "missing.h" -#include "log.h" -#include "strv.h" -#include "path-util.h" -#include "hashmap.h" -#include "conf-files.h" - -static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { - _cleanup_closedir_ DIR *dir = NULL; - _cleanup_free_ char *dirpath = NULL; - - if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0) - return -ENOMEM; - - dir = opendir(dirpath); - if (!dir) { - if (errno == ENOENT) - return 0; - return -errno; - } - - for (;;) { - struct dirent *de; - char *p; - int r; - - errno = 0; - de = readdir(dir); - if (!de && errno != 0) - return -errno; - - if (!de) - break; - - if (!dirent_is_file_with_suffix(de, suffix)) - continue; - - p = strjoin(dirpath, "/", de->d_name, NULL); - if (!p) - return -ENOMEM; - - r = hashmap_put(h, basename(p), p); - if (r == -EEXIST) { - log_debug("Skipping overridden file: %s.", p); - free(p); - } else if (r < 0) { - free(p); - return r; - } else if (r == 0) { - log_debug("Duplicate file %s", p); - free(p); - } - } - - return 0; -} - -static int base_cmp(const void *a, const void *b) { - const char *s1, *s2; - - s1 = *(char * const *)a; - s2 = *(char * const *)b; - return strcmp(basename(s1), basename(s2)); -} - -static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) { - Hashmap *fh; - char **files, **p; - int r; - - assert(strv); - assert(suffix); - - /* This alters the dirs string array */ - if (!path_strv_canonicalize_uniq(dirs)) - return -ENOMEM; - - fh = hashmap_new(string_hash_func, string_compare_func); - if (!fh) - return -ENOMEM; - - STRV_FOREACH(p, dirs) { - r = files_add(fh, root, *p, suffix); - if (r == -ENOMEM) { - hashmap_free_free(fh); - return r; - } else if (r < 0) - log_debug("Failed to search for files in %s: %s", - *p, strerror(-r)); - } - - files = hashmap_get_strv(fh); - if (files == NULL) { - hashmap_free_free(fh); - return -ENOMEM; - } - - qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); - *strv = files; - - hashmap_free(fh); - return 0; -} - -int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) { - _cleanup_strv_free_ char **copy = NULL; - - assert(strv); - assert(suffix); - - copy = strv_copy((char**) dirs); - if (!copy) - return -ENOMEM; - - return conf_files_list_strv_internal(strv, suffix, root, copy); -} diff --git a/src/libudev/conf-files.h b/src/libudev/conf-files.h deleted file mode 100644 index a0720dc2cc..0000000000 --- a/src/libudev/conf-files.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooconffileshfoo -#define fooconffileshfoo - -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - Copyright 2010-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 . -***/ - -int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs); - -#endif diff --git a/src/libudev/def.h b/src/libudev/def.h deleted file mode 100644 index d4844f4186..0000000000 --- a/src/libudev/def.h +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "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/device-nodes.c b/src/libudev/device-nodes.c deleted file mode 100644 index 5ddcaf042c..0000000000 --- a/src/libudev/device-nodes.c +++ /dev/null @@ -1,75 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of eudev, forked from systemd. - - Copyright 2008-2011 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 -#include -#include -#include - -#include "device-nodes.h" -#include "utf8.h" - -int whitelisted_char_for_devnode(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; -} - -int encode_devnode_name(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] == '\\' || !whitelisted_char_for_devnode(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; -} diff --git a/src/libudev/device-nodes.h b/src/libudev/device-nodes.h deleted file mode 100644 index 57ed97d326..0000000000 --- a/src/libudev/device-nodes.h +++ /dev/null @@ -1,23 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of eudev, forked from systemd. - - Copyright 2012 Lennart Poettering - - 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 . -***/ - -int encode_devnode_name(const char *str, char *str_enc, size_t len); -int whitelisted_char_for_devnode(char c, const char *additional); diff --git a/src/libudev/exit-status.c b/src/libudev/exit-status.c deleted file mode 100644 index 79bb8ca981..0000000000 --- a/src/libudev/exit-status.c +++ /dev/null @@ -1,48 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 - -#include "exit-status.h" -#include "set.h" -#include "macro.h" - -bool is_clean_exit(int code, int status, ExitStatusSet *success_status) { - - if (code == CLD_EXITED) - return status == 0 || - (success_status && - set_contains(success_status->status, INT_TO_PTR(status))); - - /* If a daemon does not implement handlers for some of the - * signals that's not considered an unclean shutdown */ - if (code == CLD_KILLED) - return - status == SIGHUP || - status == SIGINT || - status == SIGTERM || - status == SIGPIPE || - (success_status && - set_contains(success_status->signal, INT_TO_PTR(status))); - - return false; -} diff --git a/src/libudev/exit-status.h b/src/libudev/exit-status.h deleted file mode 100644 index e2570c65d2..0000000000 --- a/src/libudev/exit-status.h +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "set.h" - -typedef struct ExitStatusSet { - Set *status; - Set *signal; -} ExitStatusSet; - -bool is_clean_exit(int code, int status, ExitStatusSet *success_status); diff --git a/src/libudev/fileio.c b/src/libudev/fileio.c deleted file mode 100644 index fe27b23001..0000000000 --- a/src/libudev/fileio.c +++ /dev/null @@ -1,143 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include "fileio.h" -#include "util.h" -#include "strv.h" -#include "utf8.h" -#include "ctype.h" - -int write_string_stream(FILE *f, const char *line) { - assert(f); - assert(line); - - errno = 0; - - fputs(line, f); - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - -int write_string_file(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - - assert(fn); - assert(line); - - f = fopen(fn, "we"); - if (!f) - return -errno; - - return write_string_stream(f, line); -} -int read_one_line_file(const char *fn, char **line) { - _cleanup_fclose_ FILE *f = NULL; - char t[LINE_MAX], *c; - - assert(fn); - assert(line); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(t, sizeof(t), f)) { - - if (ferror(f)) - return errno ? -errno : -EIO; - - t[0] = 0; - } - - c = strdup(t); - if (!c) - return -ENOMEM; - truncate_nl(c); - - *line = c; - return 0; -} - -int read_full_file(const char *fn, char **contents, size_t *size) { - _cleanup_fclose_ FILE *f = NULL; - size_t n, l; - _cleanup_free_ char *buf = NULL; - struct stat st; - - assert(fn); - assert(contents); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (fstat(fileno(f), &st) < 0) - return -errno; - - /* Safety check */ - if (st.st_size > 4*1024*1024) - return -E2BIG; - - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; - - for (;;) { - char *t; - size_t k; - - t = realloc(buf, n+1); - if (!t) - return -ENOMEM; - - buf = t; - k = fread(buf + l, 1, n - l, f); - - if (k <= 0) { - if (ferror(f)) - return -errno; - - break; - } - - l += k; - n *= 2; - - /* Safety check */ - if (n > 4*1024*1024) - return -E2BIG; - } - - buf[l] = 0; - *contents = buf; - buf = NULL; /* do not free */ - - if (size) - *size = l; - - return 0; -} diff --git a/src/libudev/fileio.h b/src/libudev/fileio.h deleted file mode 100644 index 55c5d92486..0000000000 --- a/src/libudev/fileio.h +++ /dev/null @@ -1,27 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 - -#include "macro.h" - -int write_string_stream(FILE *f, const char *line); -int write_string_file(const char *fn, const char *line); -int read_one_line_file(const char *fn, char **line); -int read_full_file(const char *fn, char **contents, size_t *size); diff --git a/src/libudev/hashmap.c b/src/libudev/hashmap.c deleted file mode 100644 index b92c83202e..0000000000 --- a/src/libudev/hashmap.c +++ /dev/null @@ -1,550 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include - -#include "util.h" -#include "hashmap.h" -#include "macro.h" -#include "siphash24.h" - -#define INITIAL_N_BUCKETS 31 - -struct hashmap_entry { - const void *key; - void *value; - struct hashmap_entry *bucket_next, *bucket_previous; - struct hashmap_entry *iterate_next, *iterate_previous; -}; - -struct Hashmap { - hash_func_t hash_func; - compare_func_t compare_func; - - struct hashmap_entry *iterate_list_head, *iterate_list_tail; - - struct hashmap_entry ** buckets; - unsigned n_buckets, n_entries; - - uint8_t hash_key[HASH_KEY_SIZE]; - bool from_pool:1; -}; - -struct pool { - struct pool *next; - unsigned n_tiles; - unsigned n_used; -}; - -static struct pool *first_hashmap_pool = NULL; -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, 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; - - r = *first_tile; - *first_tile = * (void**) (*first_tile); - return r; - } - - if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) { - unsigned n; - size_t size; - struct pool *p; - - n = *first_pool ? (*first_pool)->n_tiles : 0; - n = MAX(at_least, n * 2); - size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size); - n = (size - ALIGN(sizeof(struct pool))) / tile_size; - - p = malloc(size); - if (!p) - return NULL; - - p->next = *first_pool; - p->n_tiles = n; - p->n_used = 0; - - *first_pool = p; - } - - i = (*first_pool)->n_used++; - - return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size; -} - -static void deallocate_tile(void **first_tile, void *p) { - * (void**) p = *first_tile; - *first_tile = p; -} - -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 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; - size_t size; - - b = is_main_thread(); - - size = ALIGN(sizeof(Hashmap)) + INITIAL_N_BUCKETS * sizeof(struct hashmap_entry*); - - if (b) { - h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size, 8); - if (!h) - return NULL; - - memzero(h, size); - } else { - h = malloc0(size); - - if (!h) - return NULL; - } - - 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; -} - -static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { - assert(h); - assert(e); - - /* Insert into hash table */ - e->bucket_next = h->buckets[hash]; - e->bucket_previous = NULL; - 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; - e->iterate_next = NULL; - if (h->iterate_list_tail) { - assert(h->iterate_list_head); - h->iterate_list_tail->iterate_next = e; - } else { - assert(!h->iterate_list_head); - h->iterate_list_head = e; - } - h->iterate_list_tail = e; - - h->n_entries++; - assert(h->n_entries >= 1); -} - -static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { - assert(h); - assert(e); - - /* Remove from iteration list */ - if (e->iterate_next) - e->iterate_next->iterate_previous = e->iterate_previous; - else - h->iterate_list_tail = e->iterate_previous; - - if (e->iterate_previous) - e->iterate_previous->iterate_next = e->iterate_next; - else - h->iterate_list_head = e->iterate_next; - - /* Remove from hash table bucket list */ - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else - h->buckets[hash] = e->bucket_next; - - assert(h->n_entries >= 1); - h->n_entries--; -} - -static void remove_entry(Hashmap *h, struct hashmap_entry *e) { - unsigned hash; - - assert(h); - assert(e); - - hash = bucket_hash(h, e->key); - unlink_entry(h, e, hash); - - if (h->from_pool) - deallocate_tile(&first_entry_tile, e); - else - free(e); -} - -void hashmap_free(Hashmap*h) { - - /* Free the hashmap, but nothing in it */ - - if (!h) - return; - - 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 - free(h); -} - -void hashmap_free_free(Hashmap *h) { - - /* Free the hashmap and all data objects in it, but not the - * keys */ - - if (!h) - return; - - hashmap_clear_free(h); - hashmap_free(h); -} - -void hashmap_clear(Hashmap *h) { - if (!h) - return; - - while (h->iterate_list_head) - remove_entry(h, h->iterate_list_head); -} - -void hashmap_clear_free(Hashmap *h) { - void *p; - - if (!h) - return; - - while ((p = hashmap_steal_first(h))) - free(p); -} - -static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { - struct hashmap_entry *e; - assert(h); - assert(hash < h->n_buckets); - - 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 = 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), 64U); - else - e = new(struct hashmap_entry, 1); - - if (!e) - return -ENOMEM; - - e->key = key; - e->value = value; - - link_entry(h, e, hash); - - return 1; -} - -void* hashmap_get(Hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - - if (!h) - return NULL; - - hash = bucket_hash(h, key); - e = hash_scan(h, hash, key); - if (!e) - return NULL; - - return e->value; -} - -bool hashmap_contains(Hashmap *h, const void *key) { - unsigned hash; - - if (!h) - return false; - - hash = bucket_hash(h, key); - return !!hash_scan(h, hash, key); -} - -void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_end; - - if (*i == ITERATOR_LAST) - goto at_end; - - if (*i == ITERATOR_FIRST && !h->iterate_list_head) - goto at_end; - - e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i; - - if (e->iterate_next) - *i = (Iterator) e->iterate_next; - else - *i = ITERATOR_LAST; - - if (key) - *key = e->key; - - return e->value; - -at_end: - *i = ITERATOR_LAST; - - if (key) - *key = NULL; - - return NULL; -} - -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_beginning; - - if (*i == ITERATOR_FIRST) - goto at_beginning; - - if (*i == ITERATOR_LAST && !h->iterate_list_tail) - goto at_beginning; - - e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; - - if (e->iterate_previous) - *i = (Iterator) e->iterate_previous; - else - *i = ITERATOR_FIRST; - - if (key) - *key = e->key; - - return e->value; - -at_beginning: - *i = ITERATOR_FIRST; - - if (key) - *key = NULL; - - return NULL; -} - -void* hashmap_steal_first(Hashmap *h) { - void *data; - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - data = h->iterate_list_head->value; - remove_entry(h, h->iterate_list_head); - - return data; -} - -unsigned hashmap_size(Hashmap *h) { - - if (!h) - return 0; - - return h->n_entries; -} - -char **hashmap_get_strv(Hashmap *h) { - char **sv; - Iterator it; - char *item; - int n; - - sv = new(char*, h->n_entries+1); - if (!sv) - return NULL; - - n = 0; - HASHMAP_FOREACH(item, h, it) - sv[n++] = item; - sv[n] = NULL; - - return sv; -} diff --git a/src/libudev/hashmap.h b/src/libudev/hashmap.h deleted file mode 100644 index 387c32243e..0000000000 --- a/src/libudev/hashmap.h +++ /dev/null @@ -1,75 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "macro.h" - -/* Pretty straightforward hash table implementation. As a minor - * optimization a NULL hashmap object will be treated as empty hashmap - * 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; - -#define ITERATOR_FIRST ((Iterator) 0) -#define ITERATOR_LAST ((Iterator) -1) - -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 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 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); -void hashmap_free(Hashmap *h); -void hashmap_free_free(Hashmap *h); - -int hashmap_put(Hashmap *h, const void *key, void *value); -void *hashmap_get(Hashmap *h, const void *key); -bool hashmap_contains(Hashmap *h, const void *key); - -unsigned hashmap_size(Hashmap *h) _pure_; - -void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); - -void hashmap_clear(Hashmap *h); -void hashmap_clear_free(Hashmap *h); - -void *hashmap_steal_first(Hashmap *h); - -char **hashmap_get_strv(Hashmap *h); - -#define HASHMAP_FOREACH(e, h, i) \ - for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL)) diff --git a/src/libudev/ioprio.h b/src/libudev/ioprio.h deleted file mode 100644 index 950e59b237..0000000000 --- a/src/libudev/ioprio.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef IOPRIO_H -#define IOPRIO_H - -/* This is minimal version of Linux' linux/ioprio.h header file, which - * is licensed GPL2 */ - -/* - * These are the io priority groups as implemented by CFQ. RT is the realtime - * class, it always gets premium service. BE is the best-effort scheduling - * class, the default for any process. IDLE is the idle scheduling class, it - * is only served when no one else is using the disk. - */ -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -#endif diff --git a/src/libudev/log.c b/src/libudev/log.c deleted file mode 100644 index cd496cf6c5..0000000000 --- a/src/libudev/log.c +++ /dev/null @@ -1,579 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "time-util.h" -#include "util.h" -#include "missing.h" -#include "macro.h" -#include "socket-util.h" - -#define SNDBUF_SIZE (8*1024*1024) - -static LogTarget log_target = LOG_TARGET_CONSOLE; -static int log_max_level = LOG_INFO; -static int log_facility = LOG_DAEMON; - -static int console_fd = STDERR_FILENO; -static int syslog_fd = -1; -static int kmsg_fd = -1; - -static bool syslog_is_stream = false; - -static bool show_color = false; -static bool show_location = false; - -/* Akin to glibc's __abort_msg; which is private and we hence cannot - * use here. */ -static char *log_abort_msg = NULL; - -void log_close_console(void) { - - if (console_fd < 0) - return; - - if (getpid() == 1) { - if (console_fd >= 3) - close_nointr_nofail(console_fd); - - console_fd = -1; - } -} - -static int log_open_console(void) { - - if (console_fd >= 0) - return 0; - - if (getpid() == 1) { - console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (console_fd < 0) - return console_fd; - } else - console_fd = STDERR_FILENO; - - return 0; -} - -void log_close_kmsg(void) { - - if (kmsg_fd < 0) - return; - - close_nointr_nofail(kmsg_fd); - kmsg_fd = -1; -} - -static int log_open_kmsg(void) { - - if (kmsg_fd >= 0) - return 0; - - kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (kmsg_fd < 0) - return -errno; - - return 0; -} - -void log_close_syslog(void) { - - if (syslog_fd < 0) - return; - - close_nointr_nofail(syslog_fd); - syslog_fd = -1; -} - -static int create_log_socket(int type) { - int fd; - - fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0); - if (fd < 0) - return -errno; - - fd_inc_sndbuf(fd, SNDBUF_SIZE); - - return fd; -} - -static int log_open_syslog(void) { - int r; - union sockaddr_union sa = { - .un.sun_family = AF_UNIX, - .un.sun_path = "/dev/log", - }; - - if (syslog_fd >= 0) - return 0; - - syslog_fd = create_log_socket(SOCK_DGRAM); - if (syslog_fd < 0) { - r = syslog_fd; - goto fail; - } - - if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - close_nointr_nofail(syslog_fd); - - /* Some legacy syslog systems still use stream - * sockets. They really shouldn't. But what can we - * do... */ - syslog_fd = create_log_socket(SOCK_STREAM); - if (syslog_fd < 0) { - r = syslog_fd; - goto fail; - } - - if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - r = -errno; - goto fail; - } - - syslog_is_stream = true; - } else - syslog_is_stream = false; - - return 0; - -fail: - log_close_syslog(); - return r; -} - -int log_open(void) { - int r; - - /* If we don't use the console we close it here, to not get - * killed by SAK. If we don't use syslog we close it here so - * that we are not confused by somebody deleting the socket in - * the fs. If we don't use /dev/kmsg we still keep it open, - * because there is no reason to close it. */ - - if (log_target == LOG_TARGET_NULL) { - log_close_syslog(); - log_close_console(); - return 0; - } - - if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) || - 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(); - if (r >= 0) { - log_close_console(); - return r; - } - } - - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SAFE || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_KMSG) { - r = log_open_kmsg(); - if (r >= 0) { - log_close_syslog(); - log_close_console(); - return r; - } - } - } - - log_close_syslog(); - - return log_open_console(); -} - -void log_set_target(LogTarget target) { - assert(target >= 0); - assert(target < _LOG_TARGET_MAX); - - log_target = target; -} - -void log_close(void) { - log_close_syslog(); - log_close_kmsg(); - log_close_console(); -} - -void log_set_max_level(int level) { - assert((level & LOG_PRIMASK) == level); - - log_max_level = level; -} - -static int write_to_console( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - const char *buffer) { - - char location[64]; - struct iovec iovec[5] = {}; - unsigned n = 0; - bool highlight; - - if (console_fd < 0) - return 0; - - highlight = LOG_PRI(level) <= LOG_ERR && show_color; - - if (show_location) { - snprintf(location, sizeof(location), "(%s:%u) ", file, line); - char_array_0(location); - IOVEC_SET_STRING(iovec[n++], location); - } - - if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON); - IOVEC_SET_STRING(iovec[n++], buffer); - if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); - IOVEC_SET_STRING(iovec[n++], "\n"); - - 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; -} - -static int write_to_syslog( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - const char *buffer) { - - char header_priority[16], header_time[64], header_pid[16]; - struct iovec iovec[5] = {}; - struct msghdr msghdr = { - .msg_iov = iovec, - .msg_iovlen = ELEMENTSOF(iovec), - }; - time_t t; - struct tm *tm; - - if (syslog_fd < 0) - return 0; - - snprintf(header_priority, sizeof(header_priority), "<%i>", level); - char_array_0(header_priority); - - t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); - tm = localtime(&t); - if (!tm) - return -EINVAL; - - if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) - return -EINVAL; - - snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); - char_array_0(header_pid); - - IOVEC_SET_STRING(iovec[0], header_priority); - IOVEC_SET_STRING(iovec[1], header_time); - IOVEC_SET_STRING(iovec[2], program_invocation_short_name); - IOVEC_SET_STRING(iovec[3], header_pid); - IOVEC_SET_STRING(iovec[4], buffer); - - /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ - if (syslog_is_stream) - iovec[4].iov_len++; - - for (;;) { - ssize_t n; - - n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL); - if (n < 0) - return -errno; - - if (!syslog_is_stream || - (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) - break; - - IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); - } - - return 1; -} - -static int write_to_kmsg( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - const char *buffer) { - - char header_priority[16], header_pid[16]; - struct iovec iovec[5] = {}; - - if (kmsg_fd < 0) - return 0; - - snprintf(header_priority, sizeof(header_priority), "<%i>", level); - char_array_0(header_priority); - - snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); - char_array_0(header_pid); - - IOVEC_SET_STRING(iovec[0], header_priority); - IOVEC_SET_STRING(iovec[1], program_invocation_short_name); - IOVEC_SET_STRING(iovec[2], header_pid); - IOVEC_SET_STRING(iovec[3], buffer); - IOVEC_SET_STRING(iovec[4], "\n"); - - if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) - return -errno; - - return 1; -} - -static int log_do_header(char *header, size_t size, - int level, - const char *file, int line, const char *func, - const char *object_name, const char *object) { - snprintf(header, size, - "PRIORITY=%i\n" - "SYSLOG_FACILITY=%i\n" - "%s%.*s%s" - "%s%.*i%s" - "%s%.*s%s" - "%s%.*s%s" - "SYSLOG_IDENTIFIER=%s\n", - LOG_PRI(level), - LOG_FAC(level), - file ? "CODE_FILE=" : "", - file ? LINE_MAX : 0, file, /* %.0s means no output */ - file ? "\n" : "", - line ? "CODE_LINE=" : "", - line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */ - line ? "\n" : "", - func ? "CODE_FUNCTION=" : "", - func ? LINE_MAX : 0, func, - func ? "\n" : "", - object ? object_name : "", - object ? LINE_MAX : 0, object, /* %.0s means no output */ - object ? "\n" : "", - program_invocation_short_name); - header[size - 1] = '\0'; - return 0; -} - -static int log_dispatch( - int level, - const char*file, - int line, - const char *func, - const char *object_name, - const char *object, - char *buffer) { - - int r = 0; - - if (log_target == LOG_TARGET_NULL) - return 0; - - /* Patch in LOG_DAEMON facility if necessary */ - if ((level & LOG_FACMASK) == 0) - level = log_facility | LOG_PRI(level); - - do { - char *e; - int k = 0; - - buffer += strspn(buffer, NEWLINE); - - if (buffer[0] == 0) - break; - - if ((e = strpbrk(buffer, NEWLINE))) - *(e++) = 0; - - if (log_target == LOG_TARGET_AUTO) - log_open_kmsg(); - - if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) { - - k = write_to_syslog(level, file, line, func, - object_name, object, buffer); - if (k < 0) { - if (k != -EAGAIN) - log_close_syslog(); - log_open_kmsg(); - } else if (k > 0) - r++; - } - - if (k <= 0 && - (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SAFE || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_KMSG)) { - - k = write_to_kmsg(level, file, line, func, - object_name, object, buffer); - if (k < 0) { - log_close_kmsg(); - log_open_console(); - } else if (k > 0) - r++; - } - - if (k <= 0) { - k = write_to_console(level, file, line, func, - object_name, object, buffer); - if (k < 0) - return k; - } - - buffer = e; - } while (buffer); - - return r; -} - -int log_metav( - int level, - const char*file, - int line, - const char *func, - const char *format, - va_list ap) { - - PROTECT_ERRNO; - char buffer[LINE_MAX]; - - if (_likely_(LOG_PRI(level) > log_max_level)) - return 0; - - vsnprintf(buffer, sizeof(buffer), format, ap); - char_array_0(buffer); - - return log_dispatch(level, file, line, func, NULL, NULL, buffer); -} - -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) { - - int r; - va_list ap; - - va_start(ap, format); - r = log_metav(level, file, line, func, format, ap); - va_end(ap); - - return r; -} - -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; - - DISABLE_WARNING_FORMAT_NONLITERAL; - snprintf(buffer, sizeof(buffer), format, text, file, line, func); - REENABLE_WARNING; - - char_array_0(buffer); - log_abort_msg = buffer; - - log_dispatch(level, file, line, func, NULL, NULL, buffer); -} - -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(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) { - log_meta(LOG_ERR, file, line, func, "Out of memory."); - 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", - [LOG_TARGET_SYSLOG] = "syslog", - [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", - [LOG_TARGET_AUTO] = "auto", - [LOG_TARGET_SAFE] = "safe", - [LOG_TARGET_NULL] = "null" -}; - -DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); diff --git a/src/libudev/log.h b/src/libudev/log.h deleted file mode 100644 index 1b2a67a030..0000000000 --- a/src/libudev/log.h +++ /dev/null @@ -1,107 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include - -#include "macro.h" - -typedef enum LogTarget{ - LOG_TARGET_CONSOLE, - LOG_TARGET_KMSG, - LOG_TARGET_JOURNAL, - LOG_TARGET_JOURNAL_OR_KMSG, - LOG_TARGET_SYSLOG, - LOG_TARGET_SYSLOG_OR_KMSG, - LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ - LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */ - LOG_TARGET_NULL, - _LOG_TARGET_MAX, - _LOG_TARGET_INVALID = -1 -} 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); - -void log_close_syslog(void); -void log_close_journal(void); -void log_close_kmsg(void); -void log_close_console(void); - -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) _printf_(5,6); - -int log_metav( - int level, - const char*file, - int line, - const char *func, - const char *format, - va_list ap) _printf_(5,0); - -int log_oom_internal( - const char *file, - int line, - const char *func); - -noreturn void log_assert_failed( - const char *text, - const char *file, - int line, - const char *func); - -noreturn void log_assert_failed_unreachable( - const char *text, - const char *file, - int line, - const char *func); - - -#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__) - -const char *log_target_to_string(LogTarget target) _const_; -LogTarget log_target_from_string(const char *s) _pure_; diff --git a/src/libudev/macro.h b/src/libudev/macro.h deleted file mode 100644 index 2deaf04092..0000000000 --- a/src/libudev/macro.h +++ /dev/null @@ -1,201 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include - -#define _printf_(a,b) __attribute__ ((format (printf, a, b))) -#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) -#define _sentinel_ __attribute__ ((sentinel)) -#define _pure_ __attribute__ ((pure)) -#define _const_ __attribute__ ((const)) -#define _packed_ __attribute__ ((packed)) -#define _malloc_ __attribute__ ((malloc)) -#define _likely_(x) (__builtin_expect(!!(x),1)) -#define _unlikely_(x) (__builtin_expect(!!(x),0)) -#define _public_ __attribute__ ((visibility("default"))) -#define _cleanup_(x) __attribute__((cleanup(x))) - - -#define DISABLE_WARNING_FORMAT_NONLITERAL \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") - -#define REENABLE_WARNING \ - _Pragma("GCC diagnostic pop") - -/* Rounds up */ - -#define ALIGN4(l) (((l) + 3) & ~3) -#define ALIGN8(l) (((l) + 7) & ~7) - -#if __SIZEOF_POINTER__ == 8 -#define ALIGN(l) ALIGN8(l) -#elif __SIZEOF_POINTER__ == 4 -#define ALIGN(l) ALIGN4(l) -#else -#error "Wut? Pointers are neither 4 nor 8 bytes long?" -#endif - -static inline size_t ALIGN_TO(size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); -} - - -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - -/* - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) \ - __extension__ ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) ); \ - }) - -#define assert_se(expr) \ - do { \ - if (_unlikely_(!(expr))) \ - log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) \ - -/* We override the glibc assert() here. */ -#undef assert -#ifdef NDEBUG -#define assert(expr) do {} while(false) -#else -#define assert(expr) assert_se(expr) -#endif - -#define assert_not_reached(t) \ - do { \ - log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) - -#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) -#define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) -#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) -#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) -#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) -#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) -#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) -#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) -#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define memzero(x,l) (memset((x), 0, (l))) - -#define char_array_0(x) x[sizeof(x)-1] = 0; - -#define IOVEC_SET_STRING(i, s) \ - do { \ - struct iovec *_i = &(i); \ - char *_s = (char *)(s); \ - _i->iov_base = _s; \ - _i->iov_len = strlen(_s); \ - } while(false) - -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; - - for (j = 0; j < n; j++) - r += i[j].iov_len; - - return r; -} - -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; - - for (j = 0; j < n; j++) { - size_t sub; - - if (_unlikely_(k <= 0)) - break; - - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } - - return k; -} - - /* Because statfs.t_type can be int on some architecures, we have to cast - * 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_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) \ - (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/missing.h b/src/libudev/missing.h deleted file mode 100644 index 471a81120c..0000000000 --- a/src/libudev/missing.h +++ /dev/null @@ -1,114 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 . -***/ - -/* Missing glibc definitions to access certain kernel APIs */ - -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "config.h" - -#ifdef ARCH_MIPS -#include -#endif - -#ifndef RLIMIT_RTTIME -#define RLIMIT_RTTIME 15 -#endif - -#ifndef BTRFS_IOCTL_MAGIC -#define BTRFS_IOCTL_MAGIC 0x94 -#endif - -#ifndef BTRFS_PATH_NAME_MAX -#define BTRFS_PATH_NAME_MAX 4087 -#endif - -#ifndef HAVE_LINUX_BTRFS_H -struct btrfs_ioctl_vol_args { - int64_t fd; - char name[BTRFS_PATH_NAME_MAX + 1]; -}; -#endif - -#ifndef BTRFS_IOC_DEVICES_READY -#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \ - struct btrfs_ioctl_vol_args) -#endif - -#ifndef MS_MOVE -#define MS_MOVE 8192 -#endif - -#ifndef MS_PRIVATE -#define MS_PRIVATE (1 << 18) -#endif - -#if !HAVE_DECL_GETTID -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} -#endif - -#ifndef MS_PRIVATE -#define MS_PRIVATE (1 << 18) -#endif - -#ifndef MS_REC -#define MS_REC 16384 -#endif - -#ifndef MAX_HANDLE_SZ -#define MAX_HANDLE_SZ 128 -#endif - -#ifndef __NR_name_to_handle_at -# if defined(__x86_64__) -# define __NR_name_to_handle_at 303 -# elif defined(__i386__) -# define __NR_name_to_handle_at 341 -# elif defined(__arm__) -# define __NR_name_to_handle_at 370 -# elif defined(__powerpc__) -# define __NR_name_to_handle_at 345 -# else -# error "__NR_name_to_handle_at is not defined" -# endif -#endif - -#if !HAVE_DECL_NAME_TO_HANDLE_AT -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); -} -#endif diff --git a/src/libudev/path-util.c b/src/libudev/path-util.c deleted file mode 100644 index 41bc20de69..0000000000 --- a/src/libudev/path-util.c +++ /dev/null @@ -1,364 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" -#include "log.h" -#include "strv.h" -#include "path-util.h" -#include "missing.h" - -bool path_is_absolute(const char *p) { - return p[0] == '/'; -} - -char *path_get_file_name(const char *p) { - char *r; - - assert(p); - - r = strrchr(p, '/'); - if (r) - return r + 1; - - return (char*) p; -} - -int path_get_parent(const char *path, char **_r) { - const char *e, *a = NULL, *b = NULL, *p; - char *r; - bool slash = false; - - assert(path); - assert(_r); - - if (!*path) - return -EINVAL; - - for (e = path; *e; e++) { - - if (!slash && *e == '/') { - a = b; - b = e; - slash = true; - } else if (slash && *e != '/') - slash = false; - } - - if (*(e-1) == '/') - p = a; - else - p = b; - - if (!p) - return -EINVAL; - - if (p == path) - r = strdup("/"); - else - r = strndup(path, p-path); - - if (!r) - return -ENOMEM; - - *_r = r; - return 0; -} - -char *path_make_absolute(const char *p, const char *prefix) { - assert(p); - - /* Makes every item in the list an absolute path by prepending - * the prefix, if specified and necessary */ - - if (path_is_absolute(p) || !prefix) - return strdup(p); - - return strjoin(prefix, "/", p, NULL); -} - -char *path_make_absolute_cwd(const char *p) { - _cleanup_free_ char *cwd = NULL; - - assert(p); - - /* Similar to path_make_absolute(), but prefixes with the - * current working directory. */ - - if (path_is_absolute(p)) - return strdup(p); - - cwd = get_current_dir_name(); - if (!cwd) - return NULL; - - return path_make_absolute(p, cwd); -} - -char **path_strv_canonicalize(char **l) { - char **s; - unsigned k = 0; - bool enomem = false; - - if (strv_isempty(l)) - return l; - - /* Goes through every item in the string list and canonicalize - * the path. This works in place and won't rollback any - * changes on failure. */ - - STRV_FOREACH(s, l) { - char *t, *u; - - t = path_make_absolute_cwd(*s); - free(*s); - *s = NULL; - - if (!t) { - enomem = true; - continue; - } - - errno = 0; - u = realpath(t, 0); - if (!u) { - if (errno == ENOENT) - u = t; - else { - free(t); - if (errno == ENOMEM || !errno) - enomem = true; - - continue; - } - } else - free(t); - - l[k++] = u; - } - - l[k] = NULL; - - if (enomem) - return NULL; - - return l; -} - -char **path_strv_canonicalize_uniq(char **l) { - if (strv_isempty(l)) - return l; - - if (!path_strv_canonicalize(l)) - return NULL; - - return strv_uniq(l); -} - -char *path_kill_slashes(char *path) { - char *f, *t; - bool slash = false; - - /* Removes redundant inner and trailing slashes. Modifies the - * passed string in-place. - * - * ///foo///bar/ becomes /foo/bar - */ - - for (f = path, t = path; *f; f++) { - - if (*f == '/') { - slash = true; - continue; - } - - if (slash) { - slash = false; - *(t++) = '/'; - } - - *(t++) = *f; - } - - /* Special rule, if we are talking of the root directory, a - trailing slash is good */ - - if (t == path && slash) - *(t++) = '/'; - - *t = 0; - return path; -} - -bool path_equal(const char *a, const char *b) { - assert(a); - assert(b); - - if ((a[0] == '/') != (b[0] == '/')) - return false; - - for (;;) { - size_t j, k; - - a += strspn(a, "/"); - b += strspn(b, "/"); - - if (*a == 0 && *b == 0) - return true; - - if (*a == 0 || *b == 0) - return false; - - j = strcspn(a, "/"); - k = strcspn(b, "/"); - - if (j != k) - return false; - - if (memcmp(a, b, j) != 0) - return false; - - a += j; - b += k; - } -} - -int path_is_mount_point(const char *t, bool allow_symlink) { - - union file_handle_union h = { - .handle.handle_bytes = MAX_HANDLE_SZ - }; - - int mount_id, mount_id_parent; - char *parent; - struct stat a, b; - int r; - - /* We are not actually interested in the file handles, but - * name_to_handle_at() also passes us the mount ID, hence use - * it but throw the handle away */ - - if (path_equal(t, "/")) - return 1; - - r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); - if (r < 0) { - if (errno == ENOSYS || errno == ENOTSUP) - /* This kernel or file system does not support - * name_to_handle_at(), hence fallback to the - * traditional stat() logic */ - goto fallback; - - if (errno == ENOENT) - return 0; - - return -errno; - } - - r = path_get_parent(t, &parent); - if (r < 0) - return r; - - h.handle.handle_bytes = MAX_HANDLE_SZ; - r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, 0); - free(parent); - if (r < 0) { - /* The parent can't do name_to_handle_at() but the - * directory we are interested in can? If so, it must - * be a mount point */ - if (errno == EOPNOTSUPP) - return 1; - - return -errno; - } - - return mount_id != mount_id_parent; - -fallback: - if (allow_symlink) - r = stat(t, &a); - else - r = lstat(t, &a); - - if (r < 0) { - if (errno == ENOENT) - return 0; - - return -errno; - } - - r = path_get_parent(t, &parent); - if (r < 0) - return r; - - r = lstat(parent, &b); - free(parent); - if (r < 0) - return -errno; - - return a.st_dev != b.st_dev; -} - -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) - return false; - - STRV_FOREACH(i, paths) { - struct stat stats; - usec_t u; - - if (stat(*i, &stats) < 0) - continue; - - u = timespec_load(&stats.st_mtim); - - /* first check */ - if (*timestamp >= u) - continue; - - log_debug("timestamp of '%s' changed", *i); - - /* update timestamp */ - if (update) { - *timestamp = u; - changed = true; - } else - return true; - } - - return changed; -} diff --git a/src/libudev/path-util.h b/src/libudev/path-util.h deleted file mode 100644 index 8e55131093..0000000000 --- a/src/libudev/path-util.h +++ /dev/null @@ -1,37 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 "time-util.h" - -char* path_get_file_name(const char *p) _pure_; -int path_get_parent(const char *path, char **parent); -bool path_is_absolute(const char *p) _pure_; -char* path_make_absolute(const char *p, const char *prefix); -char* path_make_absolute_cwd(const char *p); -char* path_kill_slashes(char *path); -bool path_equal(const char *a, const char *b) _pure_; - -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); - diff --git a/src/libudev/set.c b/src/libudev/set.c deleted file mode 100644 index 3a4f7d049a..0000000000 --- a/src/libudev/set.c +++ /dev/null @@ -1,58 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "set.h" -#include "hashmap.h" - -#define MAKE_SET(h) ((Set*) (h)) -#define MAKE_HASHMAP(s) ((Hashmap*) (s)) - -/* For now this is not much more than a wrapper around a hashmap */ - -Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { - return MAKE_SET(hashmap_new(hash_func, compare_func)); -} - -void set_free(Set* s) { - hashmap_free(MAKE_HASHMAP(s)); -} - -int set_put(Set *s, void *value) { - return hashmap_put(MAKE_HASHMAP(s), value, value); -} - -void *set_get(Set *s, void *value) { - return hashmap_get(MAKE_HASHMAP(s), value); -} - -bool set_contains(Set *s, void *value) { - return hashmap_contains(MAKE_HASHMAP(s), value); -} - -void *set_iterate(Set *s, Iterator *i) { - return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); -} - -void *set_iterate_backwards(Set *s, Iterator *i) { - return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); -} diff --git a/src/libudev/set.h b/src/libudev/set.h deleted file mode 100644 index 76383a423a..0000000000 --- a/src/libudev/set.h +++ /dev/null @@ -1,47 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 . -***/ - -/* Pretty straightforward set implementation. Internally based on the - * hashmap. That means that as a minor optimization a NULL set - * object will be treated as empty set for all read - * operations. That way it is not necessary to instantiate an object - * for each set use. */ - -#include "hashmap.h" - -typedef struct Set Set; - -Set *set_new(hash_func_t hash_func, compare_func_t compare_func); -void set_free(Set* s); -static inline void set_freep(Set **s) { - set_free(*s); -} - -int set_put(Set *s, void *value); -void *set_get(Set *s, void *value); -bool set_contains(Set *s, void *value); - -void *set_iterate(Set *s, Iterator *i); -void *set_iterate_backwards(Set *s, Iterator *i); - -#define _cleanup_set_free_ _cleanup_(set_freep) diff --git a/src/libudev/siphash24.c b/src/libudev/siphash24.c deleted file mode 100644 index f68bd283a1..0000000000 --- a/src/libudev/siphash24.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - 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 deleted file mode 100644 index 3253c179b6..0000000000 --- a/src/libudev/siphash24.h +++ /dev/null @@ -1,4 +0,0 @@ -#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 deleted file mode 100644 index 2daa3279fa..0000000000 --- a/src/libudev/socket-util.h +++ /dev/null @@ -1,36 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include -#include -#include - -union sockaddr_union { - struct sockaddr sa; - 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 deleted file mode 100644 index 51694bebb7..0000000000 --- a/src/libudev/sparse-endian.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2012 Josh Triplett - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef SPARSE_ENDIAN_H -#define SPARSE_ENDIAN_H - -#include -#include -#include - -#ifdef __CHECKER__ -#define __bitwise __attribute__((bitwise)) -#define __force __attribute__((force)) -#else -#define __bitwise -#define __force -#endif - -typedef uint16_t __bitwise le16_t; -typedef uint16_t __bitwise be16_t; -typedef uint32_t __bitwise le32_t; -typedef uint32_t __bitwise be32_t; -typedef uint64_t __bitwise le64_t; -typedef uint64_t __bitwise be64_t; - -#undef htobe16 -#undef htole16 -#undef be16toh -#undef le16toh -#undef htobe32 -#undef htole32 -#undef be32toh -#undef le32toh -#undef htobe64 -#undef htole64 -#undef be64toh -#undef le64toh - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define bswap_16_on_le(x) __bswap_16(x) -#define bswap_32_on_le(x) __bswap_32(x) -#define bswap_64_on_le(x) __bswap_64(x) -#define bswap_16_on_be(x) (x) -#define bswap_32_on_be(x) (x) -#define bswap_64_on_be(x) (x) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define bswap_16_on_le(x) (x) -#define bswap_32_on_le(x) (x) -#define bswap_64_on_le(x) (x) -#define bswap_16_on_be(x) __bswap_16(x) -#define bswap_32_on_be(x) __bswap_32(x) -#define bswap_64_on_be(x) __bswap_64(x) -#endif - -static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } -static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } -static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } - -static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } -static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } -static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } - -static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } -static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } -static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } - -static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } -static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } -static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } - -#endif /* SPARSE_ENDIAN_H */ diff --git a/src/libudev/strbuf.c b/src/libudev/strbuf.c deleted file mode 100644 index 189b01a81a..0000000000 --- a/src/libudev/strbuf.c +++ /dev/null @@ -1,200 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 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 - -#include "util.h" -#include "strbuf.h" - -/* - * Strbuf stores given strings in a single continuous allocated memory - * area. Identical strings are de-duplicated and return the same offset - * as the first string stored. If the tail of a string already exists - * in the buffer, the tail is returned. - * - * A trie (http://en.wikipedia.org/wiki/Trie) is used to maintain the - * information about the stored strings. - * - * Example of udev rules: - * $ ./udevadm test . - * ... - * read rules file: /usr/lib/udev/rules.d/99-systemd.rules - * rules contain 196608 bytes tokens (16384 * 12 bytes), 39742 bytes strings - * 23939 strings (207859 bytes), 20404 de-duplicated (171653 bytes), 3536 trie nodes used - * ... - */ - -struct strbuf *strbuf_new(void) { - struct strbuf *str; - - str = new0(struct strbuf, 1); - if (!str) - return NULL; - - str->buf = new0(char, 1); - if (!str->buf) - goto err; - str->len = 1; - - str->root = new0(struct strbuf_node, 1); - if (!str->root) - goto err; - str->nodes_count = 1; - return str; -err: - free(str->buf); - free(str->root); - free(str); - return NULL; -} - -static void strbuf_node_cleanup(struct strbuf_node *node) { - size_t i; - - for (i = 0; i < node->children_count; i++) - strbuf_node_cleanup(node->children[i].child); - free(node->children); - free(node); -} - -/* clean up trie data, leave only the string buffer */ -void strbuf_complete(struct strbuf *str) { - if (!str) - return; - if (str->root) - strbuf_node_cleanup(str->root); - str->root = NULL; -} - -/* clean up everything */ -void strbuf_cleanup(struct strbuf *str) { - if (!str) - return; - if (str->root) - strbuf_node_cleanup(str->root); - free(str->buf); - free(str); -} - -static int strbuf_children_cmp(const void* v1, const void* v2) { - const struct strbuf_child_entry *n1 = v1, *n2 = v2; - return n1->c - n2->c; -} - -static void bubbleinsert(struct strbuf_node *node, - uint8_t c, - struct strbuf_node *node_child) { - - struct strbuf_child_entry new = { - .c = c, - .child = node_child, - }; - int left = 0, right = node->children_count; - - while (right > left) { - int middle = (right + left) / 2 ; - if (strbuf_children_cmp(&node->children[middle], &new) <= 0) - left = middle + 1; - else - right = middle; - } - - memmove(node->children + left + 1, node->children + left, - sizeof(struct strbuf_child_entry) * (node->children_count - left)); - node->children[left] = new; - - node->children_count ++; -} - -/* add string, return the index/offset into the buffer */ -ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { - uint8_t c; - struct strbuf_node *node; - size_t depth; - char *buf_new; - struct strbuf_child_entry *child; - struct strbuf_node *node_child; - ssize_t off; - - if (!str->root) - return -EINVAL; - - /* search string; start from last character to find possibly matching tails */ - if (len == 0) - return 0; - str->in_count++; - str->in_len += len; - - node = str->root; - c = s[len-1]; - for (depth = 0; depth <= len; depth++) { - struct strbuf_child_entry search; - - /* match against current node */ - off = node->value_off + node->value_len - len; - if (depth == len || (node->value_len >= len && memcmp(str->buf + off, s, len) == 0)) { - str->dedup_len += len; - str->dedup_count++; - return off; - } - - /* lookup child node */ - c = s[len - 1 - depth]; - search.c = c; - child = bsearch(&search, node->children, node->children_count, - sizeof(struct strbuf_child_entry), strbuf_children_cmp); - if (!child) - break; - node = child->child; - } - - /* add new string */ - buf_new = realloc(str->buf, str->len + len+1); - if (!buf_new) - return -ENOMEM; - str->buf = buf_new; - off = str->len; - memcpy(str->buf + off, s, len); - str->len += len; - str->buf[str->len++] = '\0'; - - /* new node */ - node_child = new0(struct strbuf_node, 1); - if (!node_child) - return -ENOMEM; - node_child->value_off = off; - node_child->value_len = len; - - /* extend array, add new entry, sort for bisection */ - child = realloc(node->children, (node->children_count + 1) * sizeof(struct strbuf_child_entry)); - if (!child) { - free(node_child); - return -ENOMEM; - } - - str->nodes_count++; - - node->children = child; - bubbleinsert(node, c, node_child); - - return off; -} diff --git a/src/libudev/strbuf.h b/src/libudev/strbuf.h deleted file mode 100644 index 2347fd4328..0000000000 --- a/src/libudev/strbuf.h +++ /dev/null @@ -1,56 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 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 -#include - -struct strbuf { - char *buf; - size_t len; - struct strbuf_node *root; - - size_t nodes_count; - size_t in_count; - size_t in_len; - size_t dedup_len; - size_t dedup_count; -}; - -struct strbuf_node { - size_t value_off; - size_t value_len; - - struct strbuf_child_entry *children; - uint8_t children_count; -}; - -struct strbuf_child_entry { - uint8_t c; - struct strbuf_node *child; -}; - -struct strbuf *strbuf_new(void); -ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len); -void strbuf_complete(struct strbuf *str); -void strbuf_cleanup(struct strbuf *str); diff --git a/src/libudev/strv.c b/src/libudev/strv.c deleted file mode 100644 index da8ea8a0a6..0000000000 --- a/src/libudev/strv.c +++ /dev/null @@ -1,218 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include - -#include "util.h" -#include "strv.h" - -void strv_free(char **l) { - char **k; - - if (!l) - return; - - for (k = l; *k; k++) - free(*k); - - free(l); -} - -char **strv_copy(char * const *l) { - char **r, **k; - - k = r = new(char*, strv_length(l) + 1); - if (!r) - return NULL; - - if (l) - for (; *l; k++, l++) { - *k = strdup(*l); - if (!*k) { - strv_free(r); - return NULL; - } - } - - *k = NULL; - return r; -} - -unsigned strv_length(char * const *l) { - unsigned n = 0; - - if (!l) - return 0; - - for (; *l; l++) - n++; - - return n; -} - -char **strv_new_ap(const char *x, va_list ap) { - const char *s; - char **a; - unsigned n = 0, i = 0; - va_list aq; - - /* As a special trick we ignore all listed strings that equal - * (const char*) -1. This is supposed to be used with the - * STRV_IFNOTNULL() macro to include possibly NULL strings in - * the string list. */ - - if (x) { - n = x == (const char*) -1 ? 0 : 1; - - va_copy(aq, ap); - while ((s = va_arg(aq, const char*))) { - if (s == (const char*) -1) - continue; - - n++; - } - - va_end(aq); - } - - a = new(char*, n+1); - if (!a) - return NULL; - - if (x) { - if (x != (const char*) -1) { - a[i] = strdup(x); - if (!a[i]) - goto fail; - i++; - } - - while ((s = va_arg(ap, const char*))) { - - if (s == (const char*) -1) - continue; - - a[i] = strdup(s); - if (!a[i]) - goto fail; - - i++; - } - } - - a[i] = NULL; - - return a; - -fail: - strv_free(a); - return NULL; -} - -char **strv_new(const char *x, ...) { - char **r; - va_list ap; - - va_start(ap, x); - r = strv_new_ap(x, ap); - va_end(ap); - - return r; -} - -int strv_push(char ***l, char *value) { - char **c; - unsigned n; - - if (!value) - return 0; - - n = strv_length(*l); - c = realloc(*l, sizeof(char*) * (n + 2)); - if (!c) - return -ENOMEM; - - c[n] = value; - c[n+1] = NULL; - - *l = c; - return 0; -} - -int strv_consume(char ***l, char *value) { - int r; - - r = strv_push(l, value); - if (r < 0) - free(value); - - return r; -} - -int strv_extend(char ***l, const char *value) { - char *v; - - if (!value) - return 0; - - v = strdup(value); - if (!v) - return -ENOMEM; - - return strv_consume(l, v); -} - -char **strv_uniq(char **l) { - char **i; - - /* Drops duplicate entries. The first identical string will be - * kept, the others dropped */ - - STRV_FOREACH(i, l) - strv_remove(i+1, *i); - - return l; -} - -char **strv_remove(char **l, const char *s) { - char **f, **t; - - if (!l) - return NULL; - - assert(s); - - /* Drops every occurrence of s in the string list, edits - * in-place. */ - - for (f = t = l; *f; f++) - if (streq(*f, s)) - free(*f); - else - *(t++) = *f; - - *t = NULL; - return l; -} diff --git a/src/libudev/strv.h b/src/libudev/strv.h deleted file mode 100644 index 4cc918367e..0000000000 --- a/src/libudev/strv.h +++ /dev/null @@ -1,55 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 - -#include "macro.h" - -void strv_free(char **l); -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); -unsigned strv_length(char * const *l) _pure_; - -int strv_extend(char ***l, const char *value); -int strv_push(char ***l, char *value); -int strv_consume(char ***l, char *value); - -char **strv_remove(char **l, const char *s); -char **strv_uniq(char **l); - -char **strv_new(const char *x, ...) _sentinel_; -char **strv_new_ap(const char *x, va_list ap); - -static inline bool strv_isempty(char * const *l) { - return !l || !*l; -} - -#define STRV_FOREACH(s, l) \ - for ((s) = (l); (s) && *(s); (s)++) diff --git a/src/libudev/strxcpyx.c b/src/libudev/strxcpyx.c deleted file mode 100644 index 6efa237d4b..0000000000 --- a/src/libudev/strxcpyx.c +++ /dev/null @@ -1,100 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of eudev from systemd - - Copyright 2013 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 . -***/ - -/* - * Concatenates/copies 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. - */ - -#include -#include -#include "strxcpyx.h" - -size_t 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; - } else { - if (len > 0) { - *dest = mempcpy(*dest, src, len); - size -= len; - } - } - *dest[0] = '\0'; - return size; -} - -size_t strpcpyf(char **dest, size_t size, const char *src, ...) { - va_list va; - int i; - - va_start(va, src); - i = vsnprintf(*dest, size, src, va); - if (i < (int)size) { - *dest += i; - size -= i; - } else { - *dest += size; - size = 0; - } - va_end(va); - *dest[0] = '\0'; - return size; -} - -size_t strpcpyl(char **dest, size_t size, const char *src, ...) { - va_list va; - - va_start(va, src); - do { - size = strpcpy(dest, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - return size; -} - -size_t strscpy(char *dest, size_t size, const char *src) { - char *s; - - s = dest; - return strpcpy(&s, size, src); -} - -size_t strscpyl(char *dest, size_t size, const char *src, ...) { - va_list va; - char *s; - - va_start(va, src); - s = dest; - do { - size = strpcpy(&s, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - - return size; -} diff --git a/src/libudev/strxcpyx.h b/src/libudev/strxcpyx.h deleted file mode 100644 index e3450311df..0000000000 --- a/src/libudev/strxcpyx.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of eudev from systemd. - - Copyright 2013 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 - -#include "macro.h" - -size_t strpcpy(char **dest, size_t size, const char *src); -size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4); -size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_; -size_t strscpy(char *dest, size_t size, const char *src); -size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_; diff --git a/src/libudev/time-util.c b/src/libudev/time-util.c deleted file mode 100644 index 6f76e8c19b..0000000000 --- a/src/libudev/time-util.c +++ /dev/null @@ -1,157 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include - -#include "time-util.h" -#include "macro.h" - -usec_t now(clockid_t clock_id) { - struct timespec ts; - - assert_se(clock_gettime(clock_id, &ts) == 0); - - return timespec_load(&ts); -} - -usec_t timespec_load(const struct timespec *ts) { - assert(ts); - - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) - return USEC_INFINITY; - - if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) - return USEC_INFINITY; - - return - (usec_t) ts->tv_sec * USEC_PER_SEC + - (usec_t) ts->tv_nsec / NSEC_PER_USEC; -} - -char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "y", USEC_PER_YEAR }, - { "month", USEC_PER_MONTH }, - { "w", USEC_PER_WEEK }, - { "d", USEC_PER_DAY }, - { "h", USEC_PER_HOUR }, - { "min", USEC_PER_MINUTE }, - { "s", USEC_PER_SEC }, - { "ms", USEC_PER_MSEC }, - { "us", 1 }, - }; - - unsigned i; - char *p = buf; - bool something = false; - - assert(buf); - assert(l > 0); - - if (t == USEC_INFINITY) - return NULL; - - if (t <= 0) { - snprintf(p, l, "0"); - p[l-1] = 0; - return p; - } - - /* The result of this function can be parsed with parse_sec */ - - for (i = 0; i < ELEMENTSOF(table); i++) { - int k = 0; - size_t n; - bool done = false; - usec_t a, b; - - if (t <= 0) - break; - - if (t < accuracy && something) - break; - - if (t < table[i].usec) - continue; - - if (l <= 1) - break; - - a = t / table[i].usec; - b = t % table[i].usec; - - /* Let's see if we should shows this in dot notation */ - if (t < USEC_PER_MINUTE && b > 0) { - usec_t cc; - int j; - - j = 0; - for (cc = table[i].usec; cc > 1; cc /= 10) - j++; - - for (cc = accuracy; cc > 1; cc /= 10) { - b /= 10; - j--; - } - - if (j > 0) { - k = snprintf(p, l, - "%s"USEC_FMT".%0*llu%s", - p > buf ? " " : "", - a, - j, - (unsigned long long) b, - table[i].suffix); - - t = 0; - done = true; - } - } - - /* No? Then let's show it normally */ - if (!done) { - k = snprintf(p, l, - "%s"USEC_FMT"%s", - p > buf ? " " : "", - a, - table[i].suffix); - - t = b; - } - - n = MIN((size_t) k, l); - - l -= n; - p += n; - - something = true; - } - - *p = 0; - - return buf; -} - diff --git a/src/libudev/time-util.h b/src/libudev/time-util.h deleted file mode 100644 index 16ef25b523..0000000000 --- a/src/libudev/time-util.h +++ /dev/null @@ -1,64 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 . -***/ - -#pragma once - -#include - -typedef uint64_t usec_t; -typedef uint64_t nsec_t; - -#define USEC_FMT "%" PRIu64 - -#include "macro.h" - -typedef struct dual_timestamp { - usec_t realtime; - usec_t monotonic; -} dual_timestamp; - -#define USEC_INFINITY ((usec_t) -1) -#define NSEC_INFINITY ((nsec_t) -1) - -#define MSEC_PER_SEC 1000ULL -#define USEC_PER_SEC ((usec_t) 1000000ULL) -#define USEC_PER_MSEC ((usec_t) 1000ULL) -#define NSEC_PER_SEC ((nsec_t) 1000000000ULL) -#define NSEC_PER_MSEC ((nsec_t) 1000000ULL) -#define NSEC_PER_USEC ((nsec_t) 1000ULL) - -#define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) -#define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) -#define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) -#define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) -#define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) -#define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) -#define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) -#define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) -#define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) -#define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) -#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) -#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) - -#define FORMAT_TIMESPAN_MAX 64 - -usec_t now(clockid_t clock); - -usec_t timespec_load(const struct timespec *ts) _pure_; -char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); diff --git a/src/libudev/utf8.c b/src/libudev/utf8.c deleted file mode 100644 index 1044fb6489..0000000000 --- a/src/libudev/utf8.c +++ /dev/null @@ -1,249 +0,0 @@ -/*** - This file is part of udev, forked from systemd. - - Copyright 2008-2011 Kay Sievers - Copyright 2012 Lennart Poettering - - 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 . -***/ - -/* Parts of this file are based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include - -#include "utf8.h" -#include "util.h" - -static inline bool is_unicode_valid(uint32_t ch) { - - if (ch >= 0x110000) /* End of unicode space */ - return false; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return false; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return false; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return false; - - return true; -} - -static bool is_unicode_control(uint32_t ch) { - - /* - 0 to ' '-1 is the C0 range. - DEL=0x7F, and DEL+1 to 0x9F is C1 range. - '\t' is in C0 range, but more or less harmless and commonly used. - */ - - return (ch < ' ' && ch != '\t' && ch != '\n') || - (0x7F <= ch && ch <= 0x9F); -} - -/* 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 */ -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; -} - -bool utf8_is_printable(const char* str, size_t length) { - const uint8_t *p; - - assert(str); - - for (p = (const uint8_t*) str; length;) { - int encoded_len = utf8_encoded_valid_unichar((const char *)p); - int val = utf8_encoded_to_unichar((const char*)p); - - if (encoded_len < 0 || val < 0 || is_unicode_control(val)) - return false; - - length -= encoded_len; - p += encoded_len; - } - - return true; -} - -char *ascii_is_valid(const char *str) { - const char *p; - - assert(str); - - for (p = str; *p; p++) - if ((unsigned char) *p >= 128) - return NULL; - - return (char*) str; -} - -char *utf16_to_utf8(const void *s, size_t length) { - char *r; - const uint8_t *f; - uint8_t *t; - - r = new(char, (length*3+1)/2 + 1); - if (!r) - return NULL; - - t = (uint8_t*) r; - - for (f = s; f < (const uint8_t*) s + length; f += 2) { - uint16_t c; - - c = (f[1] << 8) | f[0]; - - if (c == 0) { - *t = 0; - return r; - } else if (c < 0x80) { - *(t++) = (uint8_t) c; - } else if (c < 0x800) { - *(t++) = (uint8_t) (0xc0 | (c >> 6)); - *(t++) = (uint8_t) (0x80 | (c & 0x3f)); - } else { - *(t++) = (uint8_t) (0xe0 | (c >> 12)); - *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); - *(t++) = (uint8_t) (0x80 | (c & 0x3f)); - } - } - - *t = 0; - - return r; -} - -/* 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; -} - -/* validate one encoded unicode char and return its length */ -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 (!is_unicode_valid(unichar)) - return -1; - - return len; -} diff --git a/src/libudev/utf8.h b/src/libudev/utf8.h deleted file mode 100644 index 9d09153c1c..0000000000 --- a/src/libudev/utf8.h +++ /dev/null @@ -1,31 +0,0 @@ -/*** - This file is part of eudev, forked from systemd - - Copyright 2012 Lennart Poettering - - 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 "macro.h" - -char *ascii_is_valid(const char *s) _pure_; - -bool utf8_is_printable(const char* str, size_t length) _pure_; - -char *utf16_to_utf8(const void *s, size_t length); - -int utf8_encoded_valid_unichar(const char *str); -int utf8_encoded_to_unichar(const char *str); diff --git a/src/libudev/util.c b/src/libudev/util.c deleted file mode 100644 index 5ff767b6a7..0000000000 --- a/src/libudev/util.c +++ /dev/null @@ -1,1187 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" -#include "ioprio.h" -#include "missing.h" -#include "log.h" -#include "strv.h" -#include "label.h" -#include "path-util.h" -#include "exit-status.h" -#include "hashmap.h" -#include "fileio.h" - -int saved_argc = 0; -char **saved_argv = NULL; - -static volatile unsigned cached_columns = 0; -static volatile unsigned cached_lines = 0; - -size_t page_size(void) { - static thread_local size_t pgsz = 0; - long r; - - if (_likely_(pgsz > 0)) - return pgsz; - - r = sysconf(_SC_PAGESIZE); - assert(r > 0); - - pgsz = (size_t) r; - return pgsz; -} - -bool streq_ptr(const char *a, const char *b) { - - /* Like streq(), but tries to make sense of NULL pointers */ - - if (a && b) - return streq(a, b); - - if (!a && !b) - return true; - - return false; -} - -char* endswith(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (memcmp(s + sl - pl, postfix, pl) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -int close_nointr(int fd) { - int r; - - assert(fd >= 0); - r = close(fd); - - /* Just ignore EINTR; a retry loop is the wrong - * thing to do on Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (_unlikely_(r < 0 && errno == EINTR)) - return 0; - else if (r >= 0) - return r; - else - return -errno; -} - -void close_nointr_nofail(int fd) { - PROTECT_ERRNO; - - /* like close_nointr() but cannot fail, and guarantees errno - * is unchanged */ - - assert_se(close_nointr(fd) == 0); -} - -int safe_close(int fd) { - - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ - - if (fd >= 0) { - PROTECT_ERRNO; - - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ - - assert_se(close_nointr(fd) != -EBADF); - } - - return -1; -} - -int unlink_noerrno(const char *path) { - PROTECT_ERRNO; - int r; - - r = unlink(path); - if (r < 0) - return -errno; - - return 0; -} - -int safe_atou(const char *s, unsigned *ret_u) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret_u); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (unsigned) l != l) - return -ERANGE; - - *ret_u = (unsigned) l; - return 0; -} - -int safe_atoi(const char *s, int *ret_i) { - char *x = NULL; - long l; - - assert(s); - assert(ret_i); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int) l != l) - return -ERANGE; - - *ret_i = (int) l; - return 0; -} - -int safe_atollu(const char *s, long long unsigned *ret_llu) { - char *x = NULL; - unsigned long long l; - - assert(s); - assert(ret_llu); - - errno = 0; - l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_llu = l; - return 0; -} - -int safe_atolli(const char *s, long long int *ret_lli) { - char *x = NULL; - long long l; - - assert(s); - assert(ret_lli); - - errno = 0; - l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_lli = l; - return 0; -} - -static size_t strcspn_escaped(const char *s, const char *reject) { - bool escaped = false; - size_t n; - - for (n=0; s[n]; n++) { - if (escaped) - escaped = false; - else if (s[n] == '\\') - escaped = true; - else if (strchr(reject, s[n])) - break; - } - /* if s ends in \, return index of previous char */ - return n - escaped; -} - -/* Split a string into words. */ -const char* split(const char **state, size_t *l, const char *separator, bool quoted) { - const char *current; - - current = *state; - - if (!*current) { - assert(**state == '\0'); - return NULL; - } - - current += strspn(current, separator); - if (!*current) { - *state = current; - return NULL; - } - - if (quoted && strchr("\'\"", *current)) { - char quotechars[2] = {*current, '\0'}; - - *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || - (current[*l + 2] && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end*/ - *state = current; - return NULL; - } - assert(current[*l + 1] == quotechars[0]); - *state = current++ + *l + 2; - } else if (quoted) { - *l = strcspn_escaped(current, separator); - *state = current + *l; - } else { - *l = strcspn(current, separator); - *state = current + *l; - } - - return current; -} - - -char *truncate_nl(char *s) { - assert(s); - - s[strcspn(s, NEWLINE)] = 0; - return s; -} - -char *strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > ((size_t) -1) - a) - return NULL; - - r = new(char, a+b+1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) { - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -char *cescape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Does C style string escaping. */ - - r = new(char, strlen(s)*4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) - - switch (*f) { - - case '\a': - *(t++) = '\\'; - *(t++) = 'a'; - break; - case '\b': - *(t++) = '\\'; - *(t++) = 'b'; - break; - case '\f': - *(t++) = '\\'; - *(t++) = 'f'; - break; - case '\n': - *(t++) = '\\'; - *(t++) = 'n'; - break; - case '\r': - *(t++) = '\\'; - *(t++) = 'r'; - break; - case '\t': - *(t++) = '\\'; - *(t++) = 't'; - break; - case '\v': - *(t++) = '\\'; - *(t++) = 'v'; - break; - case '\\': - *(t++) = '\\'; - *(t++) = '\\'; - break; - case '"': - *(t++) = '\\'; - *(t++) = '"'; - break; - case '\'': - *(t++) = '\\'; - *(t++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((*f < ' ') || (*f >= 127)) { - *(t++) = '\\'; - *(t++) = octchar((unsigned char) *f >> 6); - *(t++) = octchar((unsigned char) *f >> 3); - *(t++) = octchar((unsigned char) *f); - } else - *(t++) = *f; - break; - } - - *t = 0; - - return r; -} - -char *xescape(const char *s, const char *bad) { - char *r, *t; - const char *f; - - /* Escapes all chars in bad, in addition to \ and all special - * chars, in \xFF style escaping. May be reversed with - * cunescape. */ - - r = new(char, strlen(s) * 4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) { - - if ((*f < ' ') || (*f >= 127) || - (*f == '\\') || strchr(bad, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -_pure_ static bool ignore_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".swp"); -} - -bool ignore_file(const char *filename) { - assert(filename); - - if (endswith(filename, "~")) - return false; - - 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; - - /* - * If a TTY is in the process of being closed opening it might - * cause EIO. This is horribly awful, but unlikely to be - * changed in the kernel. Hence we work around this problem by - * retrying a couple of times. - * - * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 - */ - - assert(!(mode & O_CREAT)); - - for (;;) { - fd = open(name, mode, 0); - if (fd >= 0) - break; - - if (errno != EIO) - return -errno; - - /* Max 1s in total */ - if (c >= 20) - return -errno; - - usleep(50 * USEC_PER_MSEC); - c++; - } - - if (fd < 0) - return -errno; - - r = isatty(fd); - if (r < 0) { - close_nointr_nofail(fd); - return -errno; - } - - if (!r) { - close_nointr_nofail(fd); - return -ENOTTY; - } - - return fd; -} - -_pure_ static int is_temporary_fs(struct statfs *s) { - assert(s); - - 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) { - assert(path); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != (mode_t) -1) - if (chmod(path, mode) < 0) - return -errno; - - if (uid != (uid_t) -1 || gid != (gid_t) -1) - if (chown(path, uid, gid) < 0) - return -errno; - - return 0; -} - -bool null_or_empty(struct stat *st) { - assert(st); - - if (S_ISREG(st->st_mode) && st->st_size <= 0) - return true; - - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - return true; - - return false; -} - -int null_or_empty_path(const char *fn) { - struct stat st; - - assert(fn); - - if (stat(fn, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -int null_or_empty_fd(int fd) { - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { - assert(de); - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - if (ignore_file_allow_backup(de->d_name)) - return false; - - return endswith(de->d_name, suffix); -} - -bool nulstr_contains(const char*nulstr, const char *needle) { - const char *i; - - if (!nulstr) - return false; - - NULSTR_FOREACH(i, nulstr) - if (streq(i, needle)) - return true; - - return false; -} - -int execute_command(const char *command, char *const argv[]) -{ - - pid_t pid; - int status; - - if ((status = access(command, X_OK)) != 0) - return status; - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - return pid; - } - - if (pid == 0) { - - execvp(command, argv); - - log_error("Failed to execute %s: %m", command); - _exit(EXIT_FAILURE); - } - else while (1) - { - siginfo_t si; - - int r = waitid(P_PID, pid, &si, WEXITED); - - if (!is_clean_exit(si.si_code, si.si_status, NULL)) { - if (si.si_code == CLD_EXITED) - log_error("%s exited with exit status %i.", command, si.si_status); - else - log_error("%s terminated by signal %s.", command, signal_to_string(si.si_status)); - } else - log_debug("%s exited successfully.", command); - - return si.si_status; - - } -} - -int flush_fd(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; - - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) { - if (errno == EINTR) - continue; - - return -errno; - - } else if (r == 0) - return 0; - - l = read(fd, buf, sizeof(buf)); - if (l < 0) { - - if (errno == EINTR) - continue; - - if (errno == EAGAIN) - return 0; - - return -errno; - } else if (l == 0) - return 0; - } -} - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - const char *fn; - size_t k; - int fd; - - assert(path); - assert(_f); - assert(_temp_path); - - t = new(char, strlen(path) + 1 + 6 + 1); - if (!t) - return -ENOMEM; - - fn = path_get_file_name(path); - k = fn-path; - memcpy(t, path, k); - t[k] = '.'; - stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); - -#if HAVE_DECL_MKOSTEMP - fd = mkostemp(t, O_WRONLY|O_CLOEXEC); -#else - fd = mkstemp(t); - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif - if (fd < 0) { - free(t); - return -errno; - } - - f = fdopen(fd, "we"); - if (!f) { - unlink(t); - free(t); - return -errno; - } - - *_f = f; - *_temp_path = t; - - 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; - char *r, *p; - - va_start(ap, x); - - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - } else - l = 0; - - va_end(ap); - - r = new(char, l+1); - if (!r) - return NULL; - - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - - va_end(ap); - } else - r[0] = 0; - - return r; -} - -bool is_main_thread(void) { - static __thread int cached = 0; - - if (_unlikely_(cached == 0)) - cached = getpid() == gettid() ? 1 : -1; - - return cached > 0; -} - -static const char *const ioprio_class_table[] = { - [IOPRIO_CLASS_NONE] = "none", - [IOPRIO_CLASS_RT] = "realtime", - [IOPRIO_CLASS_BE] = "best-effort", - [IOPRIO_CLASS_IDLE] = "idle" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); - -static const char *const sigchld_code_table[] = { - [CLD_EXITED] = "exited", - [CLD_KILLED] = "killed", - [CLD_DUMPED] = "dumped", - [CLD_TRAPPED] = "trapped", - [CLD_STOPPED] = "stopped", - [CLD_CONTINUED] = "continued", -}; - -DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); - -static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", - [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); - -static const char* const sched_policy_table[] = { - [SCHED_OTHER] = "other", - [SCHED_BATCH] = "batch", - [SCHED_IDLE] = "idle", - [SCHED_FIFO] = "fifo", - [SCHED_RR] = "rr" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); - -static const char* const rlimit_table[] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" -}; - -DEFINE_STRING_TABLE_LOOKUP(rlimit, int); - -static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", - [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); - -static const char *const __signal_table[] = { - [SIGHUP] = "HUP", - [SIGINT] = "INT", - [SIGQUIT] = "QUIT", - [SIGILL] = "ILL", - [SIGTRAP] = "TRAP", - [SIGABRT] = "ABRT", - [SIGBUS] = "BUS", - [SIGFPE] = "FPE", - [SIGKILL] = "KILL", - [SIGUSR1] = "USR1", - [SIGSEGV] = "SEGV", - [SIGUSR2] = "USR2", - [SIGPIPE] = "PIPE", - [SIGALRM] = "ALRM", - [SIGTERM] = "TERM", -#ifdef SIGSTKFLT - [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ -#endif - [SIGCHLD] = "CHLD", - [SIGCONT] = "CONT", - [SIGSTOP] = "STOP", - [SIGTSTP] = "TSTP", - [SIGTTIN] = "TTIN", - [SIGTTOU] = "TTOU", - [SIGURG] = "URG", - [SIGXCPU] = "XCPU", - [SIGXFSZ] = "XFSZ", - [SIGVTALRM] = "VTALRM", - [SIGPROF] = "PROF", - [SIGWINCH] = "WINCH", - [SIGIO] = "IO", - [SIGPWR] = "PWR", - [SIGSYS] = "SYS" -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); - -const char *signal_to_string(int signo) { - static __thread char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; - const char *name; - - name = __signal_to_string(signo); - if (name) - return name; - - if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); - else - snprintf(buf, sizeof(buf), "%d", signo); - - return buf; -} - -int fd_inc_sndbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && - l == sizeof(value) && - (size_t) value >= n*2) - return 0; - - value = (int) n; - r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)); - if (r < 0) - return -errno; - - return 1; -} - -bool in_initrd(void) { - static __thread int saved = -1; - struct statfs s; - - if (saved >= 0) - return saved; - - /* We make two checks here: - * - * 1. the flag file /etc/initrd-release must exist - * 2. the root file system must be a memory file system - * - * The second check is extra paranoia, since misdetecting an - * initrd can have bad bad consequences due the initrd - * emptying when transititioning to the main systemd. - */ - - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); - - return saved; -} - -/* hey glibc, APIs with callbacks without a user pointer are so useless */ -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *, void *), void *arg) { - size_t l, u, idx; - const void *p; - int comparison; - - l = 0; - u = nmemb; - while (l < u) { - idx = (l + u) / 2; - p = (void *)(((const char *) base) + (idx * size)); - comparison = compar(key, p, arg); - if (comparison < 0) - u = idx; - else if (comparison > 0) - l = idx + 1; - else - return (void *)p; - } - return NULL; -} - -int proc_cmdline(char **ret) { - int r; - - /* disable containers for now - if (detect_container(NULL) > 0) { - char *buf, *p; - size_t sz = 0; - - r = read_full_file("/proc/1/cmdline", &buf, &sz); - if (r < 0) - return r; - - for (p = buf; p + 1 < buf + sz; p++) - if (*p == 0) - *p = ' '; - - *p = 0; - *ret = buf; - return 1; - } - */ - - r = read_one_line_file("/proc/cmdline", ret); - if (r < 0) - return r; - - return 1; -} - -int getpeercred(int fd, struct ucred *ucred) { - socklen_t n = sizeof(struct ucred); - struct ucred u; - int r; - - assert(fd >= 0); - assert(ucred); - - r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); - if (r < 0) - return -errno; - - if (n != sizeof(struct ucred)) - return -EIO; - - /* Check if the data is actually useful and not suppressed due - * to namespacing issues */ - if (u.pid <= 0) - return -ENODATA; - - *ucred = u; - return 0; -} diff --git a/src/libudev/util.h b/src/libudev/util.h deleted file mode 100644 index 5e699ca5a8..0000000000 --- a/src/libudev/util.h +++ /dev/null @@ -1,353 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2010 Lennart Poettering - - 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 . -***/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "missing.h" -#include "config.h" - -#if SIZEOF_PID_T == 4 -# define PID_FMT "%" PRIu32 -#elif SIZEOF_PID_T == 2 -# define PID_FMT "%" PRIu16 -#else -# error Unknown pid_t size -#endif - -#if SIZEOF_UID_T == 4 -# define UID_FMT "%" PRIu32 -#elif SIZEOF_UID_T == 2 -# define UID_FMT "%" PRIu16 -#else -# error Unknown uid_t size -#endif - -#if SIZEOF_GID_T == 4 -# define GID_FMT "%" PRIu32 -#elif SIZEOF_GID_T == 2 -# define GID_FMT "%" PRIu16 -#else -# error Unknown gid_t size -#endif - -#if SIZEOF_TIME_T == 8 -# define PRI_TIME PRIu64 -#elif SIZEOF_GID_T == 4 -# define PRI_TIME PRIu32 -#else -# error Unknown time_t size -#endif - -#if SIZEOF_RLIM_T == 8 -# define RLIM_FMT "%" PRIu64 -#elif SIZEOF_RLIM_T == 4 -# define RLIM_FMT "%" PRIu32 -#else -# error Unknown rlim_t size -#endif - -#include "macro.h" -#include "missing.h" - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;" -#define GLOB_CHARS "*?[" - -#define FORMAT_BYTES_MAX 8 - -#define ANSI_HIGHLIGHT_ON "\x1B[1;39m" -#define ANSI_RED_ON "\x1B[31m" -#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m" -#define ANSI_GREEN_ON "\x1B[32m" -#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" -#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m" -#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m" -#define ANSI_HIGHLIGHT_OFF "\x1B[0m" -#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" - -size_t page_size(void); -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) - -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) -#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) - -bool streq_ptr(const char *a, const char *b) _pure_; - -#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) - -#define new0(t, n) ((t*) calloc((n), sizeof(t))) -#define malloc0(n) (calloc((n), 1)) - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -static inline const char *startswith(const char *s, const char *prefix) { - if (strncmp(s, prefix, strlen(prefix)) == 0) - return s + strlen(prefix); - return NULL; -} - -char *endswith(const char *s, const char *postfix) _pure_; - -int close_nointr(int fd); -int safe_close(int fd); - -void close_nointr_nofail(int fd); - -int safe_atou(const char *s, unsigned *ret_u); -int safe_atoi(const char *s, int *ret_i); - -int safe_atollu(const char *s, unsigned long long *ret_u); -int safe_atolli(const char *s, long long int *ret_i); - -const char* split(const char **state, size_t *l, const char *separator, bool quoted); - -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, true, state) - -#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) - -char *strappend(const char *s, const char *suffix); -char *strnappend(const char *s, const char *suffix, size_t length); - -char *truncate_nl(char *s); - -char octchar(int x) _const_; -char hexchar(int x) _const_; - -char *cescape(const char *s); -char *xescape(const char *s, const char *bad); - -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; - -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) { \ - if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ - return NULL; \ - return name##_table[i]; \ - } \ - scope type name##_from_string(const char *s) { \ - type i; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ - char *s; \ - int r; \ - if (i < 0 || i > max) \ - return -ERANGE; \ - if (i < (type) ELEMENTSOF(name##_table)) { \ - s = strdup(name##_table[i]); \ - if (!s) \ - return log_oom(); \ - } else { \ - r = asprintf(&s, "%u", i); \ - if (r < 0) \ - return log_oom(); \ - } \ - *str = s; \ - return 0; \ - } \ - type name##_from_string(const char *s) { \ - type i; \ - unsigned u = 0; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - if (safe_atou(s, &u) >= 0 && u <= max) \ - return (type) u; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -int open_terminal(const char *name, int mode); - -int flush_fd(int fd); - -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_; -int null_or_empty_path(const char *fn); -int null_or_empty_fd(int fd); - -int execute_command(const char *command, char *const argv[]); - -bool nulstr_contains(const char*nulstr, const char *needle); - -char *strjoin(const char *x, ...) _sentinel_; - -bool is_main_thread(void); - -#define NULSTR_FOREACH(i, l) \ - for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) - -#define NULSTR_FOREACH_PAIR(i, j, l) \ - for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) - -int ioprio_class_to_string_alloc(int i, char **s); -int ioprio_class_from_string(const char *s); - -const char *sigchld_code_to_string(int i) _const_; -int sigchld_code_from_string(const char *s) _pure_; - -int log_facility_unshifted_to_string_alloc(int i, char **s); -int log_facility_unshifted_from_string(const char *s); - -int log_level_to_string_alloc(int i, char **s); -int log_level_from_string(const char *s); - -int sched_policy_to_string_alloc(int i, char **s); -int sched_policy_from_string(const char *s); - -const char *rlimit_to_string(int i) _const_; -int rlimit_from_string(const char *s) _pure_; - -int ip_tos_to_string_alloc(int i, char **s); -int ip_tos_from_string(const char *s); - -const char *signal_to_string(int i) _const_; - -extern int saved_argc; -extern char **saved_argv; - -int fd_inc_sndbuf(int fd, size_t n); - -bool in_initrd(void); - -static inline void freep(void *p) { - free(*(void**) p); -} - -#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ - static inline void func##p(type *p) { \ - if (*p) \ - func(*p); \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -static inline void fclosep(FILE **f) { - if (*f) - fclose(*f); -} - -static inline void closep(int *fd) { - if (*fd >= 0) - close_nointr_nofail(*fd); -} - -static inline void closedirp(DIR **d) { - if (*d) - closedir(*d); -} - -#define _cleanup_free_ _cleanup_(freep) -#define _cleanup_fclose_ _cleanup_(fclosep) -#define _cleanup_close_ _cleanup_(closep) -#define _cleanup_closedir_ _cleanup_(closedirp) - -_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b == 0 || a > ((size_t) -1) / b)) - return NULL; - - return malloc(a * b); -} - -/** - * Check if a string contains any glob patterns. - */ -_pure_ static inline bool string_is_glob(const char *p) { - return !!strpbrk(p, GLOB_CHARS); -} - -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *, void *), - void *arg); - -#define FOREACH_LINE(line, f, on_error) \ - for (;;) \ - if (!fgets(line, sizeof(line), f)) { \ - if (ferror(f)) { \ - on_error; \ - } \ - break; \ - } else - -static inline void _reset_errno_(int *saved_errno) { - errno = *saved_errno; -} - -#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno - -int unlink_noerrno(const char *path); -static inline void qsort_safe(void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *)) { - if (nmemb) { - assert(base); - qsort(base, nmemb, size, compar); - } -} - -int proc_cmdline(char **ret); -int getpeercred(int fd, struct ucred *ucred); - -union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; -}; diff --git a/src/scsi_id/Makefile.am b/src/scsi_id/Makefile.am index 6050eb9347..89fa18a550 100644 --- a/src/scsi_id/Makefile.am +++ b/src/scsi_id/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ - -I $(top_srcdir)/src/libudev \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/libudev udevlibexec_PROGRAMS = \ scsi_id diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am new file mode 100644 index 0000000000..b4c2000301 --- /dev/null +++ b/src/shared/Makefile.am @@ -0,0 +1,63 @@ +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + +AM_CPPFLAGS = \ + -include $(top_builddir)/config.h + +libudev_shared_la_SOURCES=\ + cgroup-util.c \ + conf-files.c \ + device-nodes.c \ + exit-status.c \ + fileio.c \ + hashmap.c \ + log.c \ + MurmurHash2.c \ + path-util.c \ + set.c \ + siphash24.c \ + strbuf.c \ + strv.c \ + strxcpyx.c \ + time-util.c \ + util.c \ + utf8.c \ + dev-setup.c \ + label.c \ + mkdir.c \ + smack-util.c + +noinst_HEADERS = \ + cgroup-util.h \ + conf-files.h \ + def.h \ + device-nodes.h \ + exit-status.h \ + fileio.h \ + hashmap.h \ + ioprio.h \ + log.h \ + macro.h \ + missing.h \ + MurmurHash2.h \ + path-util.h \ + set.h \ + siphash24.h \ + socket-util.h \ + sparse-endian.h \ + strbuf.h \ + strv.h \ + strxcpyx.h \ + time-util.h \ + util.h \ + utf8.h \ + dev-setup.h \ + label.h \ + mkdir.h \ + smack-util.h \ + udev-util.h + +libudev_shared_la_LDFLAGS = \ + $(AM_LDFLAGS) + +noinst_LTLIBRARIES = \ + libudev_shared.la diff --git a/src/shared/MurmurHash2.c b/src/shared/MurmurHash2.c new file mode 100644 index 0000000000..2f4149dbe9 --- /dev/null +++ b/src/shared/MurmurHash2.c @@ -0,0 +1,86 @@ +//----------------------------------------------------------------------------- +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +// Note - This code makes a few assumptions about how your machine behaves - + +// 1. We can read a 4-byte value from any address without crashing +// 2. sizeof(int) == 4 + +// And it has a few limitations - + +// 1. It will not work incrementally. +// 2. It will not produce the same results on little-endian and big-endian +// machines. + +#include "MurmurHash2.h" + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else // defined(_MSC_VER) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + const uint32_t m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + + uint32_t h = seed ^ len; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + uint32_t k = *(uint32_t*)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; +} diff --git a/src/shared/MurmurHash2.h b/src/shared/MurmurHash2.h new file mode 100644 index 0000000000..93362dd485 --- /dev/null +++ b/src/shared/MurmurHash2.h @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------------- +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +#ifndef _MURMURHASH2_H_ +#define _MURMURHASH2_H_ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +typedef unsigned char uint8_t; +typedef unsigned long uint32_t; +typedef unsigned __int64 uint64_t; + +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ); + +//----------------------------------------------------------------------------- + +#endif // _MURMURHASH2_H_ diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c new file mode 100644 index 0000000000..af6ce959c1 --- /dev/null +++ b/src/shared/cgroup-util.c @@ -0,0 +1,252 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include + +#include "cgroup-util.h" +#include "set.h" +#include "path-util.h" + +int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { + _cleanup_free_ char *fs = NULL; + FILE *f; + int r; + + assert(_f); + + r = cg_get_path(controller, path, "cgroup.procs", &fs); + if (r < 0) + return r; + + f = fopen(fs, "re"); + if (!f) + return -errno; + + *_f = f; + return 0; +} + +int cg_read_pid(FILE *f, pid_t *_pid) { + unsigned long ul; + + /* Note that the cgroup.procs might contain duplicates! See + * cgroups.txt for details. */ + + assert(f); + assert(_pid); + + errno = 0; + if (fscanf(f, "%lu", &ul) != 1) { + + if (feof(f)) + return 0; + + return errno ? -errno : -EIO; + } + + if (ul <= 0) + return -EIO; + + *_pid = (pid_t) ul; + return 1; +} + +int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) { + _cleanup_set_free_ Set *allocated_set = NULL; + bool done = false; + int r, ret = 0; + pid_t my_pid; + + assert(sig >= 0); + + /* This goes through the tasks list and kills them all. This + * is repeated until no further processes are added to the + * tasks list, to properly handle forking processes */ + + if (!s) { + s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); + if (!s) + return -ENOMEM; + } + + my_pid = getpid(); + + do { + _cleanup_fclose_ FILE *f = NULL; + pid_t pid = 0; + done = true; + + r = cg_enumerate_processes(controller, path, &f); + if (r < 0) { + if (ret >= 0 && r != -ENOENT) + return r; + + return ret; + } + + while ((r = cg_read_pid(f, &pid)) > 0) { + + if (ignore_self && pid == my_pid) + continue; + + if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) + continue; + + /* If we haven't killed this process yet, kill + * it */ + if (kill(pid, sig) < 0) { + if (ret >= 0 && errno != ESRCH) + ret = -errno; + } else if (ret == 0) { + + if (sigcont) + kill(pid, SIGCONT); + + ret = 1; + } + + done = false; + + r = set_put(s, LONG_TO_PTR(pid)); + if (r < 0) { + if (ret >= 0) + return r; + + return ret; + } + } + + if (r < 0) { + if (ret >= 0) + return r; + + return ret; + } + + /* To avoid racing against processes which fork + * quicker than we can kill them we repeat this until + * no new pids need to be killed. */ + + } while (!done); + + return ret; +} + +static const char *normalize_controller(const char *controller) { + + assert(controller); + + if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + return "systemd"; + else if (startswith(controller, "name=")) + return controller + 5; + else + return controller; +} + +static int join_path(const char *controller, const char *path, const char *suffix, char **fs) { + char *t = NULL; + + if (!isempty(controller)) { + if (!isempty(path) && !isempty(suffix)) + t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL); + else if (!isempty(path)) + t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL); + else if (!isempty(suffix)) + t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL); + else + t = strappend("/sys/fs/cgroup/", controller); + } else { + if (!isempty(path) && !isempty(suffix)) + t = strjoin(path, "/", suffix, NULL); + else if (!isempty(path)) + t = strdup(path); + else + return -EINVAL; + } + + if (!t) + return -ENOMEM; + + path_kill_slashes(t); + + *fs = t; + return 0; +} + +int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) { + const char *p; + static thread_local bool good = false; + + assert(fs); + + if (controller && !cg_controller_is_valid(controller, true)) + return -EINVAL; + + if (_unlikely_(!good)) { + int r; + + r = path_is_mount_point("/sys/fs/cgroup", false); + if (r <= 0) + return r < 0 ? r : -ENOENT; + + /* Cache this to save a few stat()s */ + good = true; + } + + p = controller ? normalize_controller(controller) : NULL; + + return join_path(p, path, suffix, fs); +} + + +#define CONTROLLER_VALID \ + DIGITS LETTERS \ + "_" + +bool cg_controller_is_valid(const char *p, bool allow_named) { + const char *t, *s; + + if (!p) + return false; + + if (allow_named) { + s = startswith(p, "name="); + if (s) + p = s; + } + + if (*p == 0 || *p == '_') + return false; + + for (t = p; *t; t++) + if (!strchr(CONTROLLER_VALID, *t)) + return false; + + if (t - p > FILENAME_MAX) + return false; + + return true; +} diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h new file mode 100644 index 0000000000..11e7308e19 --- /dev/null +++ b/src/shared/cgroup-util.h @@ -0,0 +1,53 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include + +#include "set.h" +#include "def.h" + +/* + * General rules: + * + * We accept named hierarchies in the syntax "foo" and "name=foo". + * + * We expect that named hierarchies do not conflict in name with a + * kernel hierarchy, modulo the "name=" prefix. + * + * We always generate "normalized" controller names, i.e. without the + * "name=" prefix. + * + * We require absolute cgroup paths. When returning, we will always + * generate paths with multiple adjacent / removed. + */ + +int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); +int cg_read_pid(FILE *f, pid_t *_pid); + +int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s); + +int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs); + +bool cg_controller_is_valid(const char *p, bool allow_named); diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c new file mode 100644 index 0000000000..dc4f970313 --- /dev/null +++ b/src/shared/conf-files.c @@ -0,0 +1,148 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "missing.h" +#include "log.h" +#include "strv.h" +#include "path-util.h" +#include "hashmap.h" +#include "conf-files.h" + +static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { + _cleanup_closedir_ DIR *dir = NULL; + _cleanup_free_ char *dirpath = NULL; + + if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0) + return -ENOMEM; + + dir = opendir(dirpath); + if (!dir) { + if (errno == ENOENT) + return 0; + return -errno; + } + + for (;;) { + struct dirent *de; + char *p; + int r; + + errno = 0; + de = readdir(dir); + if (!de && errno != 0) + return -errno; + + if (!de) + break; + + if (!dirent_is_file_with_suffix(de, suffix)) + continue; + + p = strjoin(dirpath, "/", de->d_name, NULL); + if (!p) + return -ENOMEM; + + r = hashmap_put(h, basename(p), p); + if (r == -EEXIST) { + log_debug("Skipping overridden file: %s.", p); + free(p); + } else if (r < 0) { + free(p); + return r; + } else if (r == 0) { + log_debug("Duplicate file %s", p); + free(p); + } + } + + return 0; +} + +static int base_cmp(const void *a, const void *b) { + const char *s1, *s2; + + s1 = *(char * const *)a; + s2 = *(char * const *)b; + return strcmp(basename(s1), basename(s2)); +} + +static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) { + Hashmap *fh; + char **files, **p; + int r; + + assert(strv); + assert(suffix); + + /* This alters the dirs string array */ + if (!path_strv_canonicalize_uniq(dirs)) + return -ENOMEM; + + fh = hashmap_new(string_hash_func, string_compare_func); + if (!fh) + return -ENOMEM; + + STRV_FOREACH(p, dirs) { + r = files_add(fh, root, *p, suffix); + if (r == -ENOMEM) { + hashmap_free_free(fh); + return r; + } else if (r < 0) + log_debug("Failed to search for files in %s: %s", + *p, strerror(-r)); + } + + files = hashmap_get_strv(fh); + if (files == NULL) { + hashmap_free_free(fh); + return -ENOMEM; + } + + qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); + *strv = files; + + hashmap_free(fh); + return 0; +} + +int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) { + _cleanup_strv_free_ char **copy = NULL; + + assert(strv); + assert(suffix); + + copy = strv_copy((char**) dirs); + if (!copy) + return -ENOMEM; + + return conf_files_list_strv_internal(strv, suffix, root, copy); +} diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h new file mode 100644 index 0000000000..a0720dc2cc --- /dev/null +++ b/src/shared/conf-files.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef fooconffileshfoo +#define fooconffileshfoo + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + Copyright 2010-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 . +***/ + +int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs); + +#endif diff --git a/src/shared/def.h b/src/shared/def.h new file mode 100644 index 0000000000..d4844f4186 --- /dev/null +++ b/src/shared/def.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 "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/shared/dev-setup.c b/src/shared/dev-setup.c new file mode 100644 index 0000000000..1a565d5470 --- /dev/null +++ b/src/shared/dev-setup.c @@ -0,0 +1,84 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + 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 +#include +#include +#include +#include + +#include "dev-setup.h" +#include "log.h" +#include "macro.h" +#include "util.h" +#include "label.h" + +static int symlink_and_label(const char *old_path, const char *new_path) { + int r; + + assert(old_path); + assert(new_path); + + r = label_context_set(new_path, S_IFLNK); + if (r < 0) + return r; + + if (symlink(old_path, new_path) < 0) + r = -errno; + + label_context_clear(); + + return r; +} + +int dev_setup(const char *prefix) { + const char *j, *k; + + static const char symlinks[] = + "-/proc/kcore\0" "/dev/core\0" + "/proc/self/fd\0" "/dev/fd\0" + "/proc/self/fd/0\0" "/dev/stdin\0" + "/proc/self/fd/1\0" "/dev/stdout\0" + "/proc/self/fd/2\0" "/dev/stderr\0"; + + NULSTR_FOREACH_PAIR(j, k, symlinks) { + if (j[0] == '-') { + j++; + + if (access(j, F_OK) < 0) + continue; + } + + if (prefix) { + _cleanup_free_ char *link_name = NULL; + + link_name = strjoin(prefix, "/", k, NULL); + if (!link_name) + return -ENOMEM; + + symlink_and_label(j, link_name); + } else + symlink_and_label(j, k); + } + + return 0; +} diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h new file mode 100644 index 0000000000..d41b6eefba --- /dev/null +++ b/src/shared/dev-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + 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 . +***/ + +int dev_setup(const char *pathprefix); diff --git a/src/shared/device-nodes.c b/src/shared/device-nodes.c new file mode 100644 index 0000000000..5ddcaf042c --- /dev/null +++ b/src/shared/device-nodes.c @@ -0,0 +1,75 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of eudev, forked from systemd. + + Copyright 2008-2011 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 +#include +#include +#include + +#include "device-nodes.h" +#include "utf8.h" + +int whitelisted_char_for_devnode(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; +} + +int encode_devnode_name(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] == '\\' || !whitelisted_char_for_devnode(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; +} diff --git a/src/shared/device-nodes.h b/src/shared/device-nodes.h new file mode 100644 index 0000000000..57ed97d326 --- /dev/null +++ b/src/shared/device-nodes.h @@ -0,0 +1,23 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of eudev, forked from systemd. + + Copyright 2012 Lennart Poettering + + 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 . +***/ + +int encode_devnode_name(const char *str, char *str_enc, size_t len); +int whitelisted_char_for_devnode(char c, const char *additional); diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c new file mode 100644 index 0000000000..79bb8ca981 --- /dev/null +++ b/src/shared/exit-status.c @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 + +#include "exit-status.h" +#include "set.h" +#include "macro.h" + +bool is_clean_exit(int code, int status, ExitStatusSet *success_status) { + + if (code == CLD_EXITED) + return status == 0 || + (success_status && + set_contains(success_status->status, INT_TO_PTR(status))); + + /* If a daemon does not implement handlers for some of the + * signals that's not considered an unclean shutdown */ + if (code == CLD_KILLED) + return + status == SIGHUP || + status == SIGINT || + status == SIGTERM || + status == SIGPIPE || + (success_status && + set_contains(success_status->signal, INT_TO_PTR(status))); + + return false; +} diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h new file mode 100644 index 0000000000..e2570c65d2 --- /dev/null +++ b/src/shared/exit-status.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 "set.h" + +typedef struct ExitStatusSet { + Set *status; + Set *signal; +} ExitStatusSet; + +bool is_clean_exit(int code, int status, ExitStatusSet *success_status); diff --git a/src/shared/fileio.c b/src/shared/fileio.c new file mode 100644 index 0000000000..fe27b23001 --- /dev/null +++ b/src/shared/fileio.c @@ -0,0 +1,143 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include "fileio.h" +#include "util.h" +#include "strv.h" +#include "utf8.h" +#include "ctype.h" + +int write_string_stream(FILE *f, const char *line) { + assert(f); + assert(line); + + errno = 0; + + fputs(line, f); + if (!endswith(line, "\n")) + fputc('\n', f); + + fflush(f); + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; +} + +int write_string_file(const char *fn, const char *line) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(line); + + f = fopen(fn, "we"); + if (!f) + return -errno; + + return write_string_stream(f, line); +} +int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; + char t[LINE_MAX], *c; + + assert(fn); + assert(line); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (!fgets(t, sizeof(t), f)) { + + if (ferror(f)) + return errno ? -errno : -EIO; + + t[0] = 0; + } + + c = strdup(t); + if (!c) + return -ENOMEM; + truncate_nl(c); + + *line = c; + return 0; +} + +int read_full_file(const char *fn, char **contents, size_t *size) { + _cleanup_fclose_ FILE *f = NULL; + size_t n, l; + _cleanup_free_ char *buf = NULL; + struct stat st; + + assert(fn); + assert(contents); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (fstat(fileno(f), &st) < 0) + return -errno; + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + n = st.st_size > 0 ? st.st_size : LINE_MAX; + l = 0; + + for (;;) { + char *t; + size_t k; + + t = realloc(buf, n+1); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + buf[l] = 0; + *contents = buf; + buf = NULL; /* do not free */ + + if (size) + *size = l; + + return 0; +} diff --git a/src/shared/fileio.h b/src/shared/fileio.h new file mode 100644 index 0000000000..55c5d92486 --- /dev/null +++ b/src/shared/fileio.h @@ -0,0 +1,27 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 + +#include "macro.h" + +int write_string_stream(FILE *f, const char *line); +int write_string_file(const char *fn, const char *line); +int read_one_line_file(const char *fn, char **line); +int read_full_file(const char *fn, char **contents, size_t *size); diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c new file mode 100644 index 0000000000..b92c83202e --- /dev/null +++ b/src/shared/hashmap.c @@ -0,0 +1,550 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include + +#include "util.h" +#include "hashmap.h" +#include "macro.h" +#include "siphash24.h" + +#define INITIAL_N_BUCKETS 31 + +struct hashmap_entry { + const void *key; + void *value; + struct hashmap_entry *bucket_next, *bucket_previous; + struct hashmap_entry *iterate_next, *iterate_previous; +}; + +struct Hashmap { + hash_func_t hash_func; + compare_func_t compare_func; + + struct hashmap_entry *iterate_list_head, *iterate_list_tail; + + struct hashmap_entry ** buckets; + unsigned n_buckets, n_entries; + + uint8_t hash_key[HASH_KEY_SIZE]; + bool from_pool:1; +}; + +struct pool { + struct pool *next; + unsigned n_tiles; + unsigned n_used; +}; + +static struct pool *first_hashmap_pool = NULL; +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, 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; + + r = *first_tile; + *first_tile = * (void**) (*first_tile); + return r; + } + + if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) { + unsigned n; + size_t size; + struct pool *p; + + n = *first_pool ? (*first_pool)->n_tiles : 0; + n = MAX(at_least, n * 2); + size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size); + n = (size - ALIGN(sizeof(struct pool))) / tile_size; + + p = malloc(size); + if (!p) + return NULL; + + p->next = *first_pool; + p->n_tiles = n; + p->n_used = 0; + + *first_pool = p; + } + + i = (*first_pool)->n_used++; + + return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size; +} + +static void deallocate_tile(void **first_tile, void *p) { + * (void**) p = *first_tile; + *first_tile = p; +} + +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 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; + size_t size; + + b = is_main_thread(); + + size = ALIGN(sizeof(Hashmap)) + INITIAL_N_BUCKETS * sizeof(struct hashmap_entry*); + + if (b) { + h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size, 8); + if (!h) + return NULL; + + memzero(h, size); + } else { + h = malloc0(size); + + if (!h) + return NULL; + } + + 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; +} + +static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { + assert(h); + assert(e); + + /* Insert into hash table */ + e->bucket_next = h->buckets[hash]; + e->bucket_previous = NULL; + 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; + e->iterate_next = NULL; + if (h->iterate_list_tail) { + assert(h->iterate_list_head); + h->iterate_list_tail->iterate_next = e; + } else { + assert(!h->iterate_list_head); + h->iterate_list_head = e; + } + h->iterate_list_tail = e; + + h->n_entries++; + assert(h->n_entries >= 1); +} + +static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { + assert(h); + assert(e); + + /* Remove from iteration list */ + if (e->iterate_next) + e->iterate_next->iterate_previous = e->iterate_previous; + else + h->iterate_list_tail = e->iterate_previous; + + if (e->iterate_previous) + e->iterate_previous->iterate_next = e->iterate_next; + else + h->iterate_list_head = e->iterate_next; + + /* Remove from hash table bucket list */ + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else + h->buckets[hash] = e->bucket_next; + + assert(h->n_entries >= 1); + h->n_entries--; +} + +static void remove_entry(Hashmap *h, struct hashmap_entry *e) { + unsigned hash; + + assert(h); + assert(e); + + hash = bucket_hash(h, e->key); + unlink_entry(h, e, hash); + + if (h->from_pool) + deallocate_tile(&first_entry_tile, e); + else + free(e); +} + +void hashmap_free(Hashmap*h) { + + /* Free the hashmap, but nothing in it */ + + if (!h) + return; + + 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 + free(h); +} + +void hashmap_free_free(Hashmap *h) { + + /* Free the hashmap and all data objects in it, but not the + * keys */ + + if (!h) + return; + + hashmap_clear_free(h); + hashmap_free(h); +} + +void hashmap_clear(Hashmap *h) { + if (!h) + return; + + while (h->iterate_list_head) + remove_entry(h, h->iterate_list_head); +} + +void hashmap_clear_free(Hashmap *h) { + void *p; + + if (!h) + return; + + while ((p = hashmap_steal_first(h))) + free(p); +} + +static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { + struct hashmap_entry *e; + assert(h); + assert(hash < h->n_buckets); + + 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 = 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), 64U); + else + e = new(struct hashmap_entry, 1); + + if (!e) + return -ENOMEM; + + e->key = key; + e->value = value; + + link_entry(h, e, hash); + + return 1; +} + +void* hashmap_get(Hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + return e->value; +} + +bool hashmap_contains(Hashmap *h, const void *key) { + unsigned hash; + + if (!h) + return false; + + hash = bucket_hash(h, key); + return !!hash_scan(h, hash, key); +} + +void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { + struct hashmap_entry *e; + + assert(i); + + if (!h) + goto at_end; + + if (*i == ITERATOR_LAST) + goto at_end; + + if (*i == ITERATOR_FIRST && !h->iterate_list_head) + goto at_end; + + e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i; + + if (e->iterate_next) + *i = (Iterator) e->iterate_next; + else + *i = ITERATOR_LAST; + + if (key) + *key = e->key; + + return e->value; + +at_end: + *i = ITERATOR_LAST; + + if (key) + *key = NULL; + + return NULL; +} + +void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { + struct hashmap_entry *e; + + assert(i); + + if (!h) + goto at_beginning; + + if (*i == ITERATOR_FIRST) + goto at_beginning; + + if (*i == ITERATOR_LAST && !h->iterate_list_tail) + goto at_beginning; + + e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; + + if (e->iterate_previous) + *i = (Iterator) e->iterate_previous; + else + *i = ITERATOR_FIRST; + + if (key) + *key = e->key; + + return e->value; + +at_beginning: + *i = ITERATOR_FIRST; + + if (key) + *key = NULL; + + return NULL; +} + +void* hashmap_steal_first(Hashmap *h) { + void *data; + + if (!h) + return NULL; + + if (!h->iterate_list_head) + return NULL; + + data = h->iterate_list_head->value; + remove_entry(h, h->iterate_list_head); + + return data; +} + +unsigned hashmap_size(Hashmap *h) { + + if (!h) + return 0; + + return h->n_entries; +} + +char **hashmap_get_strv(Hashmap *h) { + char **sv; + Iterator it; + char *item; + int n; + + sv = new(char*, h->n_entries+1); + if (!sv) + return NULL; + + n = 0; + HASHMAP_FOREACH(item, h, it) + sv[n++] = item; + sv[n] = NULL; + + return sv; +} diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h new file mode 100644 index 0000000000..387c32243e --- /dev/null +++ b/src/shared/hashmap.h @@ -0,0 +1,75 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 "macro.h" + +/* Pretty straightforward hash table implementation. As a minor + * optimization a NULL hashmap object will be treated as empty hashmap + * 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; + +#define ITERATOR_FIRST ((Iterator) 0) +#define ITERATOR_LAST ((Iterator) -1) + +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 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 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); +void hashmap_free(Hashmap *h); +void hashmap_free_free(Hashmap *h); + +int hashmap_put(Hashmap *h, const void *key, void *value); +void *hashmap_get(Hashmap *h, const void *key); +bool hashmap_contains(Hashmap *h, const void *key); + +unsigned hashmap_size(Hashmap *h) _pure_; + +void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); +void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); + +void hashmap_clear(Hashmap *h); +void hashmap_clear_free(Hashmap *h); + +void *hashmap_steal_first(Hashmap *h); + +char **hashmap_get_strv(Hashmap *h); + +#define HASHMAP_FOREACH(e, h, i) \ + for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL)) diff --git a/src/shared/ioprio.h b/src/shared/ioprio.h new file mode 100644 index 0000000000..950e59b237 --- /dev/null +++ b/src/shared/ioprio.h @@ -0,0 +1,20 @@ +#ifndef IOPRIO_H +#define IOPRIO_H + +/* This is minimal version of Linux' linux/ioprio.h header file, which + * is licensed GPL2 */ + +/* + * These are the io priority groups as implemented by CFQ. RT is the realtime + * class, it always gets premium service. BE is the best-effort scheduling + * class, the default for any process. IDLE is the idle scheduling class, it + * is only served when no one else is using the disk. + */ +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +#endif diff --git a/src/shared/label.c b/src/shared/label.c new file mode 100644 index 0000000000..dca2a21228 --- /dev/null +++ b/src/shared/label.c @@ -0,0 +1,247 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include + +#include "label.h" +#include "util.h" +#include "path-util.h" + +#ifdef HAVE_SELINUX +#include +#include +#include + +static struct selabel_handle *label_hnd = NULL; +static int use_selinux_cached = -1; + +bool use_selinux(void) { + if (use_selinux_cached < 0) + use_selinux_cached = is_selinux_enabled() > 0; + + return use_selinux_cached; +} +#endif + +int label_init(const char *prefix) { + int r = 0; + +#ifdef HAVE_SELINUX + usec_t before_timestamp, after_timestamp; + struct mallinfo before_mallinfo, after_mallinfo; + + if (!use_selinux()) + return 0; + + if (label_hnd) + return 0; + + before_mallinfo = mallinfo(); + before_timestamp = now(CLOCK_MONOTONIC); + + if (prefix) { + struct selinux_opt options[] = { + { .type = SELABEL_OPT_SUBSET, .value = prefix }, + }; + + label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); + } else + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + + if (!label_hnd) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Failed to initialize SELinux context: %m"); + r = security_getenforce() == 1 ? -errno : 0; + } else { + char timespan[FORMAT_TIMESPAN_MAX]; + int l; + + after_timestamp = now(CLOCK_MONOTONIC); + after_mallinfo = mallinfo(); + + l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0; + + log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.", + format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0), + (l+1023)/1024); + } +#endif + + return r; +} + +int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { + int r = 0; + +#ifdef HAVE_SELINUX + struct stat st; + security_context_t fcon; + + if (!use_selinux() || !label_hnd) + return 0; + + r = lstat(path, &st); + if (r == 0) { + r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); + + /* If there's no label to set, then exit without warning */ + if (r < 0 && errno == ENOENT) + return 0; + + if (r == 0) { + r = lsetfilecon(path, fcon); + freecon(fcon); + + /* If the FS doesn't support labels, then exit without warning */ + if (r < 0 && errno == ENOTSUP) + return 0; + } + } + + if (r < 0) { + /* Ignore ENOENT in some cases */ + if (ignore_enoent && errno == ENOENT) + return 0; + + if (ignore_erofs && errno == EROFS) + return 0; + + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Unable to fix label of %s: %m", path); + r = security_getenforce() == 1 ? -errno : 0; + } +#endif + + return r; +} + +void label_finish(void) { + +#ifdef HAVE_SELINUX + if (use_selinux() && label_hnd) + selabel_close(label_hnd); +#endif +} + +int label_context_set(const char *path, mode_t mode) { + int r = 0; + +#ifdef HAVE_SELINUX + security_context_t filecon = NULL; + + if (!use_selinux() || !label_hnd) + return 0; + + r = selabel_lookup_raw(label_hnd, &filecon, path, mode); + if (r < 0 && errno != ENOENT) + r = -errno; + else if (r == 0) { + r = setfscreatecon(filecon); + if (r < 0) { + log_error("Failed to set SELinux file context on %s: %m", path); + r = -errno; + } + + freecon(filecon); + } + + if (r < 0 && security_getenforce() == 0) + r = 0; +#endif + + return r; +} + +void label_context_clear(void) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + setfscreatecon(NULL); +#endif +} + +int label_mkdir(const char *path, mode_t mode, bool apply) { + + /* Creates a directory and labels it according to the SELinux policy */ +#ifdef HAVE_SELINUX + int r; + security_context_t fcon = NULL; + + if (!apply || !use_selinux() || !label_hnd) + goto skipped; + + if (path_is_absolute(path)) + r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR); + else { + char *newpath; + + newpath = path_make_absolute_cwd(path); + if (!newpath) + return -ENOMEM; + + r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR); + free(newpath); + } + + if (r == 0) + r = setfscreatecon(fcon); + + if (r < 0 && errno != ENOENT) { + log_error("Failed to set security context %s for %s: %m", fcon, path); + + if (security_getenforce() == 1) { + r = -errno; + goto finish; + } + } + + r = mkdir(path, mode); + if (r < 0) + r = -errno; + +finish: + setfscreatecon(NULL); + freecon(fcon); + + return r; + +skipped: +#endif + return mkdir(path, mode) < 0 ? -errno : 0; +} + +int label_apply(const char *path, const char *label) { + int r = 0; + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return 0; + + r = setfilecon(path, (char *)label); +#endif + return r; +} diff --git a/src/shared/label.h b/src/shared/label.h new file mode 100644 index 0000000000..a8dbcdc8b7 --- /dev/null +++ b/src/shared/label.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include + +int label_init(const char *prefix); +void label_finish(void); + +int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs); + +int label_context_set(const char *path, mode_t mode); +void label_context_clear(void); + +int label_mkdir(const char *path, mode_t mode, bool apply); + +int label_apply(const char *path, const char *label); diff --git a/src/shared/log.c b/src/shared/log.c new file mode 100644 index 0000000000..cd496cf6c5 --- /dev/null +++ b/src/shared/log.c @@ -0,0 +1,579 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "time-util.h" +#include "util.h" +#include "missing.h" +#include "macro.h" +#include "socket-util.h" + +#define SNDBUF_SIZE (8*1024*1024) + +static LogTarget log_target = LOG_TARGET_CONSOLE; +static int log_max_level = LOG_INFO; +static int log_facility = LOG_DAEMON; + +static int console_fd = STDERR_FILENO; +static int syslog_fd = -1; +static int kmsg_fd = -1; + +static bool syslog_is_stream = false; + +static bool show_color = false; +static bool show_location = false; + +/* Akin to glibc's __abort_msg; which is private and we hence cannot + * use here. */ +static char *log_abort_msg = NULL; + +void log_close_console(void) { + + if (console_fd < 0) + return; + + if (getpid() == 1) { + if (console_fd >= 3) + close_nointr_nofail(console_fd); + + console_fd = -1; + } +} + +static int log_open_console(void) { + + if (console_fd >= 0) + return 0; + + if (getpid() == 1) { + console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (console_fd < 0) + return console_fd; + } else + console_fd = STDERR_FILENO; + + return 0; +} + +void log_close_kmsg(void) { + + if (kmsg_fd < 0) + return; + + close_nointr_nofail(kmsg_fd); + kmsg_fd = -1; +} + +static int log_open_kmsg(void) { + + if (kmsg_fd >= 0) + return 0; + + kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (kmsg_fd < 0) + return -errno; + + return 0; +} + +void log_close_syslog(void) { + + if (syslog_fd < 0) + return; + + close_nointr_nofail(syslog_fd); + syslog_fd = -1; +} + +static int create_log_socket(int type) { + int fd; + + fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + fd_inc_sndbuf(fd, SNDBUF_SIZE); + + return fd; +} + +static int log_open_syslog(void) { + int r; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/dev/log", + }; + + if (syslog_fd >= 0) + return 0; + + syslog_fd = create_log_socket(SOCK_DGRAM); + if (syslog_fd < 0) { + r = syslog_fd; + goto fail; + } + + if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + close_nointr_nofail(syslog_fd); + + /* Some legacy syslog systems still use stream + * sockets. They really shouldn't. But what can we + * do... */ + syslog_fd = create_log_socket(SOCK_STREAM); + if (syslog_fd < 0) { + r = syslog_fd; + goto fail; + } + + if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + r = -errno; + goto fail; + } + + syslog_is_stream = true; + } else + syslog_is_stream = false; + + return 0; + +fail: + log_close_syslog(); + return r; +} + +int log_open(void) { + int r; + + /* If we don't use the console we close it here, to not get + * killed by SAK. If we don't use syslog we close it here so + * that we are not confused by somebody deleting the socket in + * the fs. If we don't use /dev/kmsg we still keep it open, + * because there is no reason to close it. */ + + if (log_target == LOG_TARGET_NULL) { + log_close_syslog(); + log_close_console(); + return 0; + } + + if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) || + 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(); + if (r >= 0) { + log_close_console(); + return r; + } + } + + if (log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_SAFE || + log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_KMSG) { + r = log_open_kmsg(); + if (r >= 0) { + log_close_syslog(); + log_close_console(); + return r; + } + } + } + + log_close_syslog(); + + return log_open_console(); +} + +void log_set_target(LogTarget target) { + assert(target >= 0); + assert(target < _LOG_TARGET_MAX); + + log_target = target; +} + +void log_close(void) { + log_close_syslog(); + log_close_kmsg(); + log_close_console(); +} + +void log_set_max_level(int level) { + assert((level & LOG_PRIMASK) == level); + + log_max_level = level; +} + +static int write_to_console( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char location[64]; + struct iovec iovec[5] = {}; + unsigned n = 0; + bool highlight; + + if (console_fd < 0) + return 0; + + highlight = LOG_PRI(level) <= LOG_ERR && show_color; + + if (show_location) { + snprintf(location, sizeof(location), "(%s:%u) ", file, line); + char_array_0(location); + IOVEC_SET_STRING(iovec[n++], location); + } + + if (highlight) + IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON); + IOVEC_SET_STRING(iovec[n++], buffer); + if (highlight) + IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); + IOVEC_SET_STRING(iovec[n++], "\n"); + + 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; +} + +static int write_to_syslog( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char header_priority[16], header_time[64], header_pid[16]; + struct iovec iovec[5] = {}; + struct msghdr msghdr = { + .msg_iov = iovec, + .msg_iovlen = ELEMENTSOF(iovec), + }; + time_t t; + struct tm *tm; + + if (syslog_fd < 0) + return 0; + + snprintf(header_priority, sizeof(header_priority), "<%i>", level); + char_array_0(header_priority); + + t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); + tm = localtime(&t); + if (!tm) + return -EINVAL; + + if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) + return -EINVAL; + + snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); + char_array_0(header_pid); + + IOVEC_SET_STRING(iovec[0], header_priority); + IOVEC_SET_STRING(iovec[1], header_time); + IOVEC_SET_STRING(iovec[2], program_invocation_short_name); + IOVEC_SET_STRING(iovec[3], header_pid); + IOVEC_SET_STRING(iovec[4], buffer); + + /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ + if (syslog_is_stream) + iovec[4].iov_len++; + + for (;;) { + ssize_t n; + + n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL); + if (n < 0) + return -errno; + + if (!syslog_is_stream || + (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) + break; + + IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); + } + + return 1; +} + +static int write_to_kmsg( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char header_priority[16], header_pid[16]; + struct iovec iovec[5] = {}; + + if (kmsg_fd < 0) + return 0; + + snprintf(header_priority, sizeof(header_priority), "<%i>", level); + char_array_0(header_priority); + + snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); + char_array_0(header_pid); + + IOVEC_SET_STRING(iovec[0], header_priority); + IOVEC_SET_STRING(iovec[1], program_invocation_short_name); + IOVEC_SET_STRING(iovec[2], header_pid); + IOVEC_SET_STRING(iovec[3], buffer); + IOVEC_SET_STRING(iovec[4], "\n"); + + if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) + return -errno; + + return 1; +} + +static int log_do_header(char *header, size_t size, + int level, + const char *file, int line, const char *func, + const char *object_name, const char *object) { + snprintf(header, size, + "PRIORITY=%i\n" + "SYSLOG_FACILITY=%i\n" + "%s%.*s%s" + "%s%.*i%s" + "%s%.*s%s" + "%s%.*s%s" + "SYSLOG_IDENTIFIER=%s\n", + LOG_PRI(level), + LOG_FAC(level), + file ? "CODE_FILE=" : "", + file ? LINE_MAX : 0, file, /* %.0s means no output */ + file ? "\n" : "", + line ? "CODE_LINE=" : "", + line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */ + line ? "\n" : "", + func ? "CODE_FUNCTION=" : "", + func ? LINE_MAX : 0, func, + func ? "\n" : "", + object ? object_name : "", + object ? LINE_MAX : 0, object, /* %.0s means no output */ + object ? "\n" : "", + program_invocation_short_name); + header[size - 1] = '\0'; + return 0; +} + +static int log_dispatch( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + char *buffer) { + + int r = 0; + + if (log_target == LOG_TARGET_NULL) + return 0; + + /* Patch in LOG_DAEMON facility if necessary */ + if ((level & LOG_FACMASK) == 0) + level = log_facility | LOG_PRI(level); + + do { + char *e; + int k = 0; + + buffer += strspn(buffer, NEWLINE); + + if (buffer[0] == 0) + break; + + if ((e = strpbrk(buffer, NEWLINE))) + *(e++) = 0; + + if (log_target == LOG_TARGET_AUTO) + log_open_kmsg(); + + if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_SYSLOG) { + + k = write_to_syslog(level, file, line, func, + object_name, object, buffer); + if (k < 0) { + if (k != -EAGAIN) + log_close_syslog(); + log_open_kmsg(); + } else if (k > 0) + r++; + } + + if (k <= 0 && + (log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_SAFE || + log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_KMSG)) { + + k = write_to_kmsg(level, file, line, func, + object_name, object, buffer); + if (k < 0) { + log_close_kmsg(); + log_open_console(); + } else if (k > 0) + r++; + } + + if (k <= 0) { + k = write_to_console(level, file, line, func, + object_name, object, buffer); + if (k < 0) + return k; + } + + buffer = e; + } while (buffer); + + return r; +} + +int log_metav( + int level, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) { + + PROTECT_ERRNO; + char buffer[LINE_MAX]; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + vsnprintf(buffer, sizeof(buffer), format, ap); + char_array_0(buffer); + + return log_dispatch(level, file, line, func, NULL, NULL, buffer); +} + +int log_meta( + int level, + const char*file, + int line, + const char *func, + const char *format, ...) { + + int r; + va_list ap; + + va_start(ap, format); + r = log_metav(level, file, line, func, format, ap); + va_end(ap); + + return r; +} + +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; + + DISABLE_WARNING_FORMAT_NONLITERAL; + snprintf(buffer, sizeof(buffer), format, text, file, line, func); + REENABLE_WARNING; + + char_array_0(buffer); + log_abort_msg = buffer; + + log_dispatch(level, file, line, func, NULL, NULL, buffer); +} + +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(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) { + log_meta(LOG_ERR, file, line, func, "Out of memory."); + 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", + [LOG_TARGET_SYSLOG] = "syslog", + [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", + [LOG_TARGET_AUTO] = "auto", + [LOG_TARGET_SAFE] = "safe", + [LOG_TARGET_NULL] = "null" +}; + +DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); diff --git a/src/shared/log.h b/src/shared/log.h new file mode 100644 index 0000000000..1b2a67a030 --- /dev/null +++ b/src/shared/log.h @@ -0,0 +1,107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include + +#include "macro.h" + +typedef enum LogTarget{ + LOG_TARGET_CONSOLE, + LOG_TARGET_KMSG, + LOG_TARGET_JOURNAL, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_SYSLOG, + LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ + LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */ + LOG_TARGET_NULL, + _LOG_TARGET_MAX, + _LOG_TARGET_INVALID = -1 +} 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); + +void log_close_syslog(void); +void log_close_journal(void); +void log_close_kmsg(void); +void log_close_console(void); + +int log_meta( + int level, + const char*file, + int line, + const char *func, + const char *format, ...) _printf_(5,6); + +int log_metav( + int level, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) _printf_(5,0); + +int log_oom_internal( + const char *file, + int line, + const char *func); + +noreturn void log_assert_failed( + const char *text, + const char *file, + int line, + const char *func); + +noreturn void log_assert_failed_unreachable( + const char *text, + const char *file, + int line, + const char *func); + + +#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__) + +const char *log_target_to_string(LogTarget target) _const_; +LogTarget log_target_from_string(const char *s) _pure_; diff --git a/src/shared/macro.h b/src/shared/macro.h new file mode 100644 index 0000000000..2deaf04092 --- /dev/null +++ b/src/shared/macro.h @@ -0,0 +1,201 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include + +#define _printf_(a,b) __attribute__ ((format (printf, a, b))) +#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#define _sentinel_ __attribute__ ((sentinel)) +#define _pure_ __attribute__ ((pure)) +#define _const_ __attribute__ ((const)) +#define _packed_ __attribute__ ((packed)) +#define _malloc_ __attribute__ ((malloc)) +#define _likely_(x) (__builtin_expect(!!(x),1)) +#define _unlikely_(x) (__builtin_expect(!!(x),0)) +#define _public_ __attribute__ ((visibility("default"))) +#define _cleanup_(x) __attribute__((cleanup(x))) + + +#define DISABLE_WARNING_FORMAT_NONLITERAL \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") + +#define REENABLE_WARNING \ + _Pragma("GCC diagnostic pop") + +/* Rounds up */ + +#define ALIGN4(l) (((l) + 3) & ~3) +#define ALIGN8(l) (((l) + 7) & ~7) + +#if __SIZEOF_POINTER__ == 8 +#define ALIGN(l) ALIGN8(l) +#elif __SIZEOF_POINTER__ == 4 +#define ALIGN(l) ALIGN4(l) +#else +#error "Wut? Pointers are neither 4 nor 8 bytes long?" +#endif + +static inline size_t ALIGN_TO(size_t l, size_t ali) { + return ((l + ali - 1) & ~(ali - 1)); +} + + +#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) + +/* + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) \ + __extension__ ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) ); \ + }) + +#define assert_se(expr) \ + do { \ + if (_unlikely_(!(expr))) \ + log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) \ + +/* We override the glibc assert() here. */ +#undef assert +#ifdef NDEBUG +#define assert(expr) do {} while(false) +#else +#define assert(expr) assert_se(expr) +#endif + +#define assert_not_reached(t) \ + do { \ + log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) + +#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) +#define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) +#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) +#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) +#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) +#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) +#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) +#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define memzero(x,l) (memset((x), 0, (l))) + +#define char_array_0(x) x[sizeof(x)-1] = 0; + +#define IOVEC_SET_STRING(i, s) \ + do { \ + struct iovec *_i = &(i); \ + char *_s = (char *)(s); \ + _i->iov_base = _s; \ + _i->iov_len = strlen(_s); \ + } while(false) + +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { + unsigned j; + size_t r = 0; + + for (j = 0; j < n; j++) + r += i[j].iov_len; + + return r; +} + +static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { + unsigned j; + + for (j = 0; j < n; j++) { + size_t sub; + + if (_unlikely_(k <= 0)) + break; + + sub = MIN(i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t*) i[j].iov_base + sub; + k -= sub; + } + + return k; +} + + /* Because statfs.t_type can be int on some architecures, we have to cast + * 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_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) \ + (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/shared/missing.h b/src/shared/missing.h new file mode 100644 index 0000000000..471a81120c --- /dev/null +++ b/src/shared/missing.h @@ -0,0 +1,114 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +/* Missing glibc definitions to access certain kernel APIs */ + +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "config.h" + +#ifdef ARCH_MIPS +#include +#endif + +#ifndef RLIMIT_RTTIME +#define RLIMIT_RTTIME 15 +#endif + +#ifndef BTRFS_IOCTL_MAGIC +#define BTRFS_IOCTL_MAGIC 0x94 +#endif + +#ifndef BTRFS_PATH_NAME_MAX +#define BTRFS_PATH_NAME_MAX 4087 +#endif + +#ifndef HAVE_LINUX_BTRFS_H +struct btrfs_ioctl_vol_args { + int64_t fd; + char name[BTRFS_PATH_NAME_MAX + 1]; +}; +#endif + +#ifndef BTRFS_IOC_DEVICES_READY +#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \ + struct btrfs_ioctl_vol_args) +#endif + +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif + +#ifndef MS_PRIVATE +#define MS_PRIVATE (1 << 18) +#endif + +#if !HAVE_DECL_GETTID +static inline pid_t gettid(void) { + return (pid_t) syscall(SYS_gettid); +} +#endif + +#ifndef MS_PRIVATE +#define MS_PRIVATE (1 << 18) +#endif + +#ifndef MS_REC +#define MS_REC 16384 +#endif + +#ifndef MAX_HANDLE_SZ +#define MAX_HANDLE_SZ 128 +#endif + +#ifndef __NR_name_to_handle_at +# if defined(__x86_64__) +# define __NR_name_to_handle_at 303 +# elif defined(__i386__) +# define __NR_name_to_handle_at 341 +# elif defined(__arm__) +# define __NR_name_to_handle_at 370 +# elif defined(__powerpc__) +# define __NR_name_to_handle_at 345 +# else +# error "__NR_name_to_handle_at is not defined" +# endif +#endif + +#if !HAVE_DECL_NAME_TO_HANDLE_AT +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { + return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); +} +#endif diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c new file mode 100644 index 0000000000..770ee994c4 --- /dev/null +++ b/src/shared/mkdir.c @@ -0,0 +1,157 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include +#include +#include + +#include "label.h" +#include "util.h" +#include "mkdir.h" + +static int is_dir(const char* path) { + struct stat st; + + if (stat(path, &st) < 0) + return -errno; + + return S_ISDIR(st.st_mode); +} + + +char* path_startswith(const char *path, const char *prefix) { + assert(path); + assert(prefix); + + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; + + for (;;) { + size_t a, b; + + path += strspn(path, "/"); + prefix += strspn(prefix, "/"); + + if (*prefix == 0) + return (char*) path; + + if (*path == 0) + return NULL; + + a = strcspn(path, "/"); + b = strcspn(prefix, "/"); + + if (a != b) + return NULL; + + if (memcmp(path, prefix, a) != 0) + return NULL; + + path += a; + prefix += b; + } +} + +static int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, bool apply) { + const char *p, *e; + int r; + + assert(path); + + if (prefix && !path_startswith(path, prefix)) + return -ENOTDIR; + + /* return immediately if directory exists */ + e = strrchr(path, '/'); + if (!e) + return -EINVAL; + + if (e == path) + return 0; + + char buf[PATH_MAX + 1]; + p = buf; + assert(e-path < sizeof(buf)); + memcpy(buf, path, e-path); + buf[e-path] = 0; + + r = is_dir(p); + if (r > 0) + return 0; + if (r == 0) + return -ENOTDIR; + + /* create every parent directory in the path, except the last component */ + p = path + strspn(path, "/"); + for (;;) { + char t[strlen(path) + 1]; + + e = p + strcspn(p, "/"); + p = e + strspn(e, "/"); + + /* Is this the last component? If so, then we're + * done */ + if (*p == 0) + return 0; + + memcpy(t, path, e - path); + t[e-path] = 0; + + if (prefix && path_startswith(prefix, t)) + continue; + + r = label_mkdir(t, mode, apply); + if (r < 0 && errno != EEXIST) + return -errno; + } +} + +int mkdir_parents(const char *path, mode_t mode) { + return mkdir_parents_internal(NULL, path, mode, false); +} + +int mkdir_parents_label(const char *path, mode_t mode) { + return mkdir_parents_internal(NULL, path, mode, true); +} + +static int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, bool apply) { + int r; + + /* Like mkdir -p */ + + r = mkdir_parents_internal(prefix, path, mode, apply); + if (r < 0) + return r; + + r = label_mkdir(path, mode, apply); + if (r < 0 && (errno != EEXIST || is_dir(path) <= 0)) + return -errno; + + return 0; +} + +int mkdir_p(const char *path, mode_t mode) { + return mkdir_p_internal(NULL, path, mode, false); +} diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h new file mode 100644 index 0000000000..24ffa6364c --- /dev/null +++ b/src/shared/mkdir.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foomkdirhfoo +#define foomkdirhfoo + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +char* path_startswith(const char *path, const char *prefix) _pure_; +int mkdir_parents(const char *path, mode_t mode); +int mkdir_parents_label(const char *path, mode_t mode); +int mkdir_p(const char *path, mode_t mode); +#endif diff --git a/src/shared/path-util.c b/src/shared/path-util.c new file mode 100644 index 0000000000..41bc20de69 --- /dev/null +++ b/src/shared/path-util.c @@ -0,0 +1,364 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "log.h" +#include "strv.h" +#include "path-util.h" +#include "missing.h" + +bool path_is_absolute(const char *p) { + return p[0] == '/'; +} + +char *path_get_file_name(const char *p) { + char *r; + + assert(p); + + r = strrchr(p, '/'); + if (r) + return r + 1; + + return (char*) p; +} + +int path_get_parent(const char *path, char **_r) { + const char *e, *a = NULL, *b = NULL, *p; + char *r; + bool slash = false; + + assert(path); + assert(_r); + + if (!*path) + return -EINVAL; + + for (e = path; *e; e++) { + + if (!slash && *e == '/') { + a = b; + b = e; + slash = true; + } else if (slash && *e != '/') + slash = false; + } + + if (*(e-1) == '/') + p = a; + else + p = b; + + if (!p) + return -EINVAL; + + if (p == path) + r = strdup("/"); + else + r = strndup(path, p-path); + + if (!r) + return -ENOMEM; + + *_r = r; + return 0; +} + +char *path_make_absolute(const char *p, const char *prefix) { + assert(p); + + /* Makes every item in the list an absolute path by prepending + * the prefix, if specified and necessary */ + + if (path_is_absolute(p) || !prefix) + return strdup(p); + + return strjoin(prefix, "/", p, NULL); +} + +char *path_make_absolute_cwd(const char *p) { + _cleanup_free_ char *cwd = NULL; + + assert(p); + + /* Similar to path_make_absolute(), but prefixes with the + * current working directory. */ + + if (path_is_absolute(p)) + return strdup(p); + + cwd = get_current_dir_name(); + if (!cwd) + return NULL; + + return path_make_absolute(p, cwd); +} + +char **path_strv_canonicalize(char **l) { + char **s; + unsigned k = 0; + bool enomem = false; + + if (strv_isempty(l)) + return l; + + /* Goes through every item in the string list and canonicalize + * the path. This works in place and won't rollback any + * changes on failure. */ + + STRV_FOREACH(s, l) { + char *t, *u; + + t = path_make_absolute_cwd(*s); + free(*s); + *s = NULL; + + if (!t) { + enomem = true; + continue; + } + + errno = 0; + u = realpath(t, 0); + if (!u) { + if (errno == ENOENT) + u = t; + else { + free(t); + if (errno == ENOMEM || !errno) + enomem = true; + + continue; + } + } else + free(t); + + l[k++] = u; + } + + l[k] = NULL; + + if (enomem) + return NULL; + + return l; +} + +char **path_strv_canonicalize_uniq(char **l) { + if (strv_isempty(l)) + return l; + + if (!path_strv_canonicalize(l)) + return NULL; + + return strv_uniq(l); +} + +char *path_kill_slashes(char *path) { + char *f, *t; + bool slash = false; + + /* Removes redundant inner and trailing slashes. Modifies the + * passed string in-place. + * + * ///foo///bar/ becomes /foo/bar + */ + + for (f = path, t = path; *f; f++) { + + if (*f == '/') { + slash = true; + continue; + } + + if (slash) { + slash = false; + *(t++) = '/'; + } + + *(t++) = *f; + } + + /* Special rule, if we are talking of the root directory, a + trailing slash is good */ + + if (t == path && slash) + *(t++) = '/'; + + *t = 0; + return path; +} + +bool path_equal(const char *a, const char *b) { + assert(a); + assert(b); + + if ((a[0] == '/') != (b[0] == '/')) + return false; + + for (;;) { + size_t j, k; + + a += strspn(a, "/"); + b += strspn(b, "/"); + + if (*a == 0 && *b == 0) + return true; + + if (*a == 0 || *b == 0) + return false; + + j = strcspn(a, "/"); + k = strcspn(b, "/"); + + if (j != k) + return false; + + if (memcmp(a, b, j) != 0) + return false; + + a += j; + b += k; + } +} + +int path_is_mount_point(const char *t, bool allow_symlink) { + + union file_handle_union h = { + .handle.handle_bytes = MAX_HANDLE_SZ + }; + + int mount_id, mount_id_parent; + char *parent; + struct stat a, b; + int r; + + /* We are not actually interested in the file handles, but + * name_to_handle_at() also passes us the mount ID, hence use + * it but throw the handle away */ + + if (path_equal(t, "/")) + return 1; + + r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); + if (r < 0) { + if (errno == ENOSYS || errno == ENOTSUP) + /* This kernel or file system does not support + * name_to_handle_at(), hence fallback to the + * traditional stat() logic */ + goto fallback; + + if (errno == ENOENT) + return 0; + + return -errno; + } + + r = path_get_parent(t, &parent); + if (r < 0) + return r; + + h.handle.handle_bytes = MAX_HANDLE_SZ; + r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, 0); + free(parent); + if (r < 0) { + /* The parent can't do name_to_handle_at() but the + * directory we are interested in can? If so, it must + * be a mount point */ + if (errno == EOPNOTSUPP) + return 1; + + return -errno; + } + + return mount_id != mount_id_parent; + +fallback: + if (allow_symlink) + r = stat(t, &a); + else + r = lstat(t, &a); + + if (r < 0) { + if (errno == ENOENT) + return 0; + + return -errno; + } + + r = path_get_parent(t, &parent); + if (r < 0) + return r; + + r = lstat(parent, &b); + free(parent); + if (r < 0) + return -errno; + + return a.st_dev != b.st_dev; +} + +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) + return false; + + STRV_FOREACH(i, paths) { + struct stat stats; + usec_t u; + + if (stat(*i, &stats) < 0) + continue; + + u = timespec_load(&stats.st_mtim); + + /* first check */ + if (*timestamp >= u) + continue; + + log_debug("timestamp of '%s' changed", *i); + + /* update timestamp */ + if (update) { + *timestamp = u; + changed = true; + } else + return true; + } + + return changed; +} diff --git a/src/shared/path-util.h b/src/shared/path-util.h new file mode 100644 index 0000000000..8e55131093 --- /dev/null +++ b/src/shared/path-util.h @@ -0,0 +1,37 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010-2012 Lennart Poettering + + 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 "time-util.h" + +char* path_get_file_name(const char *p) _pure_; +int path_get_parent(const char *path, char **parent); +bool path_is_absolute(const char *p) _pure_; +char* path_make_absolute(const char *p, const char *prefix); +char* path_make_absolute_cwd(const char *p); +char* path_kill_slashes(char *path); +bool path_equal(const char *a, const char *b) _pure_; + +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); + diff --git a/src/shared/set.c b/src/shared/set.c new file mode 100644 index 0000000000..3a4f7d049a --- /dev/null +++ b/src/shared/set.c @@ -0,0 +1,58 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 "set.h" +#include "hashmap.h" + +#define MAKE_SET(h) ((Set*) (h)) +#define MAKE_HASHMAP(s) ((Hashmap*) (s)) + +/* For now this is not much more than a wrapper around a hashmap */ + +Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { + return MAKE_SET(hashmap_new(hash_func, compare_func)); +} + +void set_free(Set* s) { + hashmap_free(MAKE_HASHMAP(s)); +} + +int set_put(Set *s, void *value) { + return hashmap_put(MAKE_HASHMAP(s), value, value); +} + +void *set_get(Set *s, void *value) { + return hashmap_get(MAKE_HASHMAP(s), value); +} + +bool set_contains(Set *s, void *value) { + return hashmap_contains(MAKE_HASHMAP(s), value); +} + +void *set_iterate(Set *s, Iterator *i) { + return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); +} + +void *set_iterate_backwards(Set *s, Iterator *i) { + return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); +} diff --git a/src/shared/set.h b/src/shared/set.h new file mode 100644 index 0000000000..76383a423a --- /dev/null +++ b/src/shared/set.h @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +/* Pretty straightforward set implementation. Internally based on the + * hashmap. That means that as a minor optimization a NULL set + * object will be treated as empty set for all read + * operations. That way it is not necessary to instantiate an object + * for each set use. */ + +#include "hashmap.h" + +typedef struct Set Set; + +Set *set_new(hash_func_t hash_func, compare_func_t compare_func); +void set_free(Set* s); +static inline void set_freep(Set **s) { + set_free(*s); +} + +int set_put(Set *s, void *value); +void *set_get(Set *s, void *value); +bool set_contains(Set *s, void *value); + +void *set_iterate(Set *s, Iterator *i); +void *set_iterate_backwards(Set *s, Iterator *i); + +#define _cleanup_set_free_ _cleanup_(set_freep) diff --git a/src/shared/siphash24.c b/src/shared/siphash24.c new file mode 100644 index 0000000000..f68bd283a1 --- /dev/null +++ b/src/shared/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/shared/siphash24.h b/src/shared/siphash24.h new file mode 100644 index 0000000000..3253c179b6 --- /dev/null +++ b/src/shared/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/shared/smack-util.c b/src/shared/smack-util.c new file mode 100644 index 0000000000..2711041c7e --- /dev/null +++ b/src/shared/smack-util.c @@ -0,0 +1,89 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2013 Intel Corporation + + Author: Auke Kok + + 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 +#ifdef HAVE_XATTR +#include +#endif + +#include "smack-util.h" + +bool use_smack(void) { +#ifdef HAVE_SMACK + static int use_smack_cached = -1; + + if (use_smack_cached < 0) + use_smack_cached = access("/sys/fs/smackfs/", F_OK) >= 0; + + return use_smack_cached; +#else + return false; +#endif + +} + +int smack_label_path(const char *path, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + if (label) + return setxattr(path, "security.SMACK64", label, strlen(label), 0); + else + return lremovexattr(path, "security.SMACK64"); +#else + return 0; +#endif +} + +int smack_label_fd(int fd, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + return fsetxattr(fd, "security.SMACK64", label, strlen(label), 0); +#else + return 0; +#endif +} + +int smack_label_ip_out_fd(int fd, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + return fsetxattr(fd, "security.SMACK64IPOUT", label, strlen(label), 0); +#else + return 0; +#endif +} + +int smack_label_ip_in_fd(int fd, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + return fsetxattr(fd, "security.SMACK64IPIN", label, strlen(label), 0); +#else + return 0; +#endif +} diff --git a/src/shared/smack-util.h b/src/shared/smack-util.h new file mode 100644 index 0000000000..88704894e7 --- /dev/null +++ b/src/shared/smack-util.h @@ -0,0 +1,28 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2013 Intel Corporation + + Author: Auke Kok + + 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 + +bool use_smack(void); +int smack_label_path(const char *path, const char *label); +int smack_label_fd(int fd, const char *label); +int smack_label_ip_in_fd(int fd, const char *label); +int smack_label_ip_out_fd(int fd, const char *label); diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h new file mode 100644 index 0000000000..2daa3279fa --- /dev/null +++ b/src/shared/socket-util.h @@ -0,0 +1,36 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include +#include +#include + +union sockaddr_union { + struct sockaddr sa; + 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/shared/sparse-endian.h b/src/shared/sparse-endian.h new file mode 100644 index 0000000000..51694bebb7 --- /dev/null +++ b/src/shared/sparse-endian.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2012 Josh Triplett + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef SPARSE_ENDIAN_H +#define SPARSE_ENDIAN_H + +#include +#include +#include + +#ifdef __CHECKER__ +#define __bitwise __attribute__((bitwise)) +#define __force __attribute__((force)) +#else +#define __bitwise +#define __force +#endif + +typedef uint16_t __bitwise le16_t; +typedef uint16_t __bitwise be16_t; +typedef uint32_t __bitwise le32_t; +typedef uint32_t __bitwise be32_t; +typedef uint64_t __bitwise le64_t; +typedef uint64_t __bitwise be64_t; + +#undef htobe16 +#undef htole16 +#undef be16toh +#undef le16toh +#undef htobe32 +#undef htole32 +#undef be32toh +#undef le32toh +#undef htobe64 +#undef htole64 +#undef be64toh +#undef le64toh + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define bswap_16_on_le(x) __bswap_16(x) +#define bswap_32_on_le(x) __bswap_32(x) +#define bswap_64_on_le(x) __bswap_64(x) +#define bswap_16_on_be(x) (x) +#define bswap_32_on_be(x) (x) +#define bswap_64_on_be(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define bswap_16_on_le(x) (x) +#define bswap_32_on_le(x) (x) +#define bswap_64_on_le(x) (x) +#define bswap_16_on_be(x) __bswap_16(x) +#define bswap_32_on_be(x) __bswap_32(x) +#define bswap_64_on_be(x) __bswap_64(x) +#endif + +static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } +static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } +static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } + +static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } +static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } +static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } + +static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } +static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } +static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } + +static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } +static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } +static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } + +#endif /* SPARSE_ENDIAN_H */ diff --git a/src/shared/strbuf.c b/src/shared/strbuf.c new file mode 100644 index 0000000000..189b01a81a --- /dev/null +++ b/src/shared/strbuf.c @@ -0,0 +1,200 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 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 + +#include "util.h" +#include "strbuf.h" + +/* + * Strbuf stores given strings in a single continuous allocated memory + * area. Identical strings are de-duplicated and return the same offset + * as the first string stored. If the tail of a string already exists + * in the buffer, the tail is returned. + * + * A trie (http://en.wikipedia.org/wiki/Trie) is used to maintain the + * information about the stored strings. + * + * Example of udev rules: + * $ ./udevadm test . + * ... + * read rules file: /usr/lib/udev/rules.d/99-systemd.rules + * rules contain 196608 bytes tokens (16384 * 12 bytes), 39742 bytes strings + * 23939 strings (207859 bytes), 20404 de-duplicated (171653 bytes), 3536 trie nodes used + * ... + */ + +struct strbuf *strbuf_new(void) { + struct strbuf *str; + + str = new0(struct strbuf, 1); + if (!str) + return NULL; + + str->buf = new0(char, 1); + if (!str->buf) + goto err; + str->len = 1; + + str->root = new0(struct strbuf_node, 1); + if (!str->root) + goto err; + str->nodes_count = 1; + return str; +err: + free(str->buf); + free(str->root); + free(str); + return NULL; +} + +static void strbuf_node_cleanup(struct strbuf_node *node) { + size_t i; + + for (i = 0; i < node->children_count; i++) + strbuf_node_cleanup(node->children[i].child); + free(node->children); + free(node); +} + +/* clean up trie data, leave only the string buffer */ +void strbuf_complete(struct strbuf *str) { + if (!str) + return; + if (str->root) + strbuf_node_cleanup(str->root); + str->root = NULL; +} + +/* clean up everything */ +void strbuf_cleanup(struct strbuf *str) { + if (!str) + return; + if (str->root) + strbuf_node_cleanup(str->root); + free(str->buf); + free(str); +} + +static int strbuf_children_cmp(const void* v1, const void* v2) { + const struct strbuf_child_entry *n1 = v1, *n2 = v2; + return n1->c - n2->c; +} + +static void bubbleinsert(struct strbuf_node *node, + uint8_t c, + struct strbuf_node *node_child) { + + struct strbuf_child_entry new = { + .c = c, + .child = node_child, + }; + int left = 0, right = node->children_count; + + while (right > left) { + int middle = (right + left) / 2 ; + if (strbuf_children_cmp(&node->children[middle], &new) <= 0) + left = middle + 1; + else + right = middle; + } + + memmove(node->children + left + 1, node->children + left, + sizeof(struct strbuf_child_entry) * (node->children_count - left)); + node->children[left] = new; + + node->children_count ++; +} + +/* add string, return the index/offset into the buffer */ +ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { + uint8_t c; + struct strbuf_node *node; + size_t depth; + char *buf_new; + struct strbuf_child_entry *child; + struct strbuf_node *node_child; + ssize_t off; + + if (!str->root) + return -EINVAL; + + /* search string; start from last character to find possibly matching tails */ + if (len == 0) + return 0; + str->in_count++; + str->in_len += len; + + node = str->root; + c = s[len-1]; + for (depth = 0; depth <= len; depth++) { + struct strbuf_child_entry search; + + /* match against current node */ + off = node->value_off + node->value_len - len; + if (depth == len || (node->value_len >= len && memcmp(str->buf + off, s, len) == 0)) { + str->dedup_len += len; + str->dedup_count++; + return off; + } + + /* lookup child node */ + c = s[len - 1 - depth]; + search.c = c; + child = bsearch(&search, node->children, node->children_count, + sizeof(struct strbuf_child_entry), strbuf_children_cmp); + if (!child) + break; + node = child->child; + } + + /* add new string */ + buf_new = realloc(str->buf, str->len + len+1); + if (!buf_new) + return -ENOMEM; + str->buf = buf_new; + off = str->len; + memcpy(str->buf + off, s, len); + str->len += len; + str->buf[str->len++] = '\0'; + + /* new node */ + node_child = new0(struct strbuf_node, 1); + if (!node_child) + return -ENOMEM; + node_child->value_off = off; + node_child->value_len = len; + + /* extend array, add new entry, sort for bisection */ + child = realloc(node->children, (node->children_count + 1) * sizeof(struct strbuf_child_entry)); + if (!child) { + free(node_child); + return -ENOMEM; + } + + str->nodes_count++; + + node->children = child; + bubbleinsert(node, c, node_child); + + return off; +} diff --git a/src/shared/strbuf.h b/src/shared/strbuf.h new file mode 100644 index 0000000000..2347fd4328 --- /dev/null +++ b/src/shared/strbuf.h @@ -0,0 +1,56 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 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 +#include + +struct strbuf { + char *buf; + size_t len; + struct strbuf_node *root; + + size_t nodes_count; + size_t in_count; + size_t in_len; + size_t dedup_len; + size_t dedup_count; +}; + +struct strbuf_node { + size_t value_off; + size_t value_len; + + struct strbuf_child_entry *children; + uint8_t children_count; +}; + +struct strbuf_child_entry { + uint8_t c; + struct strbuf_node *child; +}; + +struct strbuf *strbuf_new(void); +ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len); +void strbuf_complete(struct strbuf *str); +void strbuf_cleanup(struct strbuf *str); diff --git a/src/shared/strv.c b/src/shared/strv.c new file mode 100644 index 0000000000..da8ea8a0a6 --- /dev/null +++ b/src/shared/strv.c @@ -0,0 +1,218 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include + +#include "util.h" +#include "strv.h" + +void strv_free(char **l) { + char **k; + + if (!l) + return; + + for (k = l; *k; k++) + free(*k); + + free(l); +} + +char **strv_copy(char * const *l) { + char **r, **k; + + k = r = new(char*, strv_length(l) + 1); + if (!r) + return NULL; + + if (l) + for (; *l; k++, l++) { + *k = strdup(*l); + if (!*k) { + strv_free(r); + return NULL; + } + } + + *k = NULL; + return r; +} + +unsigned strv_length(char * const *l) { + unsigned n = 0; + + if (!l) + return 0; + + for (; *l; l++) + n++; + + return n; +} + +char **strv_new_ap(const char *x, va_list ap) { + const char *s; + char **a; + unsigned n = 0, i = 0; + va_list aq; + + /* As a special trick we ignore all listed strings that equal + * (const char*) -1. This is supposed to be used with the + * STRV_IFNOTNULL() macro to include possibly NULL strings in + * the string list. */ + + if (x) { + n = x == (const char*) -1 ? 0 : 1; + + va_copy(aq, ap); + while ((s = va_arg(aq, const char*))) { + if (s == (const char*) -1) + continue; + + n++; + } + + va_end(aq); + } + + a = new(char*, n+1); + if (!a) + return NULL; + + if (x) { + if (x != (const char*) -1) { + a[i] = strdup(x); + if (!a[i]) + goto fail; + i++; + } + + while ((s = va_arg(ap, const char*))) { + + if (s == (const char*) -1) + continue; + + a[i] = strdup(s); + if (!a[i]) + goto fail; + + i++; + } + } + + a[i] = NULL; + + return a; + +fail: + strv_free(a); + return NULL; +} + +char **strv_new(const char *x, ...) { + char **r; + va_list ap; + + va_start(ap, x); + r = strv_new_ap(x, ap); + va_end(ap); + + return r; +} + +int strv_push(char ***l, char *value) { + char **c; + unsigned n; + + if (!value) + return 0; + + n = strv_length(*l); + c = realloc(*l, sizeof(char*) * (n + 2)); + if (!c) + return -ENOMEM; + + c[n] = value; + c[n+1] = NULL; + + *l = c; + return 0; +} + +int strv_consume(char ***l, char *value) { + int r; + + r = strv_push(l, value); + if (r < 0) + free(value); + + return r; +} + +int strv_extend(char ***l, const char *value) { + char *v; + + if (!value) + return 0; + + v = strdup(value); + if (!v) + return -ENOMEM; + + return strv_consume(l, v); +} + +char **strv_uniq(char **l) { + char **i; + + /* Drops duplicate entries. The first identical string will be + * kept, the others dropped */ + + STRV_FOREACH(i, l) + strv_remove(i+1, *i); + + return l; +} + +char **strv_remove(char **l, const char *s) { + char **f, **t; + + if (!l) + return NULL; + + assert(s); + + /* Drops every occurrence of s in the string list, edits + * in-place. */ + + for (f = t = l; *f; f++) + if (streq(*f, s)) + free(*f); + else + *(t++) = *f; + + *t = NULL; + return l; +} diff --git a/src/shared/strv.h b/src/shared/strv.h new file mode 100644 index 0000000000..4cc918367e --- /dev/null +++ b/src/shared/strv.h @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 + +#include "macro.h" + +void strv_free(char **l); +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); +unsigned strv_length(char * const *l) _pure_; + +int strv_extend(char ***l, const char *value); +int strv_push(char ***l, char *value); +int strv_consume(char ***l, char *value); + +char **strv_remove(char **l, const char *s); +char **strv_uniq(char **l); + +char **strv_new(const char *x, ...) _sentinel_; +char **strv_new_ap(const char *x, va_list ap); + +static inline bool strv_isempty(char * const *l) { + return !l || !*l; +} + +#define STRV_FOREACH(s, l) \ + for ((s) = (l); (s) && *(s); (s)++) diff --git a/src/shared/strxcpyx.c b/src/shared/strxcpyx.c new file mode 100644 index 0000000000..6efa237d4b --- /dev/null +++ b/src/shared/strxcpyx.c @@ -0,0 +1,100 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of eudev from systemd + + Copyright 2013 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 . +***/ + +/* + * Concatenates/copies 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. + */ + +#include +#include +#include "strxcpyx.h" + +size_t 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; + } else { + if (len > 0) { + *dest = mempcpy(*dest, src, len); + size -= len; + } + } + *dest[0] = '\0'; + return size; +} + +size_t strpcpyf(char **dest, size_t size, const char *src, ...) { + va_list va; + int i; + + va_start(va, src); + i = vsnprintf(*dest, size, src, va); + if (i < (int)size) { + *dest += i; + size -= i; + } else { + *dest += size; + size = 0; + } + va_end(va); + *dest[0] = '\0'; + return size; +} + +size_t strpcpyl(char **dest, size_t size, const char *src, ...) { + va_list va; + + va_start(va, src); + do { + size = strpcpy(dest, size, src); + src = va_arg(va, char *); + } while (src != NULL); + va_end(va); + return size; +} + +size_t strscpy(char *dest, size_t size, const char *src) { + char *s; + + s = dest; + return strpcpy(&s, size, src); +} + +size_t strscpyl(char *dest, size_t size, const char *src, ...) { + va_list va; + char *s; + + va_start(va, src); + s = dest; + do { + size = strpcpy(&s, size, src); + src = va_arg(va, char *); + } while (src != NULL); + va_end(va); + + return size; +} diff --git a/src/shared/strxcpyx.h b/src/shared/strxcpyx.h new file mode 100644 index 0000000000..e3450311df --- /dev/null +++ b/src/shared/strxcpyx.h @@ -0,0 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of eudev from systemd. + + Copyright 2013 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 + +#include "macro.h" + +size_t strpcpy(char **dest, size_t size, const char *src); +size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4); +size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_; +size_t strscpy(char *dest, size_t size, const char *src); +size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_; diff --git a/src/shared/time-util.c b/src/shared/time-util.c new file mode 100644 index 0000000000..6f76e8c19b --- /dev/null +++ b/src/shared/time-util.c @@ -0,0 +1,157 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include + +#include "time-util.h" +#include "macro.h" + +usec_t now(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load(&ts); +} + +usec_t timespec_load(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return USEC_INFINITY; + + if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + return USEC_INFINITY; + + return + (usec_t) ts->tv_sec * USEC_PER_SEC + + (usec_t) ts->tv_nsec / NSEC_PER_USEC; +} + +char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "y", USEC_PER_YEAR }, + { "month", USEC_PER_MONTH }, + { "w", USEC_PER_WEEK }, + { "d", USEC_PER_DAY }, + { "h", USEC_PER_HOUR }, + { "min", USEC_PER_MINUTE }, + { "s", USEC_PER_SEC }, + { "ms", USEC_PER_MSEC }, + { "us", 1 }, + }; + + unsigned i; + char *p = buf; + bool something = false; + + assert(buf); + assert(l > 0); + + if (t == USEC_INFINITY) + return NULL; + + if (t <= 0) { + snprintf(p, l, "0"); + p[l-1] = 0; + return p; + } + + /* The result of this function can be parsed with parse_sec */ + + for (i = 0; i < ELEMENTSOF(table); i++) { + int k = 0; + size_t n; + bool done = false; + usec_t a, b; + + if (t <= 0) + break; + + if (t < accuracy && something) + break; + + if (t < table[i].usec) + continue; + + if (l <= 1) + break; + + a = t / table[i].usec; + b = t % table[i].usec; + + /* Let's see if we should shows this in dot notation */ + if (t < USEC_PER_MINUTE && b > 0) { + usec_t cc; + int j; + + j = 0; + for (cc = table[i].usec; cc > 1; cc /= 10) + j++; + + for (cc = accuracy; cc > 1; cc /= 10) { + b /= 10; + j--; + } + + if (j > 0) { + k = snprintf(p, l, + "%s"USEC_FMT".%0*llu%s", + p > buf ? " " : "", + a, + j, + (unsigned long long) b, + table[i].suffix); + + t = 0; + done = true; + } + } + + /* No? Then let's show it normally */ + if (!done) { + k = snprintf(p, l, + "%s"USEC_FMT"%s", + p > buf ? " " : "", + a, + table[i].suffix); + + t = b; + } + + n = MIN((size_t) k, l); + + l -= n; + p += n; + + something = true; + } + + *p = 0; + + return buf; +} + diff --git a/src/shared/time-util.h b/src/shared/time-util.h new file mode 100644 index 0000000000..16ef25b523 --- /dev/null +++ b/src/shared/time-util.h @@ -0,0 +1,64 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +#pragma once + +#include + +typedef uint64_t usec_t; +typedef uint64_t nsec_t; + +#define USEC_FMT "%" PRIu64 + +#include "macro.h" + +typedef struct dual_timestamp { + usec_t realtime; + usec_t monotonic; +} dual_timestamp; + +#define USEC_INFINITY ((usec_t) -1) +#define NSEC_INFINITY ((nsec_t) -1) + +#define MSEC_PER_SEC 1000ULL +#define USEC_PER_SEC ((usec_t) 1000000ULL) +#define USEC_PER_MSEC ((usec_t) 1000ULL) +#define NSEC_PER_SEC ((nsec_t) 1000000000ULL) +#define NSEC_PER_MSEC ((nsec_t) 1000000ULL) +#define NSEC_PER_USEC ((nsec_t) 1000ULL) + +#define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) +#define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) +#define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) +#define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) +#define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) +#define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) +#define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) +#define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) +#define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) +#define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) +#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) +#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) + +#define FORMAT_TIMESPAN_MAX 64 + +usec_t now(clockid_t clock); + +usec_t timespec_load(const struct timespec *ts) _pure_; +char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h new file mode 100644 index 0000000000..5f09ce181f --- /dev/null +++ b/src/shared/udev-util.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + 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 "udev.h" +#include "util.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref); + +#define _cleanup_udev_unref_ _cleanup_(udev_unrefp) +#define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp) +#define _cleanup_udev_enumerate_unref_ _cleanup_(udev_enumerate_unrefp) +#define _cleanup_udev_event_unref_ _cleanup_(udev_event_unrefp) +#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp) +#define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp) +#define _cleanup_udev_monitor_unref_ _cleanup_(udev_monitor_unrefp) +#define _cleanup_udev_list_cleanup_ _cleanup_(udev_list_cleanup) diff --git a/src/shared/utf8.c b/src/shared/utf8.c new file mode 100644 index 0000000000..1044fb6489 --- /dev/null +++ b/src/shared/utf8.c @@ -0,0 +1,249 @@ +/*** + This file is part of udev, forked from systemd. + + Copyright 2008-2011 Kay Sievers + Copyright 2012 Lennart Poettering + + 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 . +***/ + +/* Parts of this file are based on the GLIB utf8 validation functions. The + * original license text follows. */ + +/* gutf8.c - Operations on UTF-8 strings. + * + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "utf8.h" +#include "util.h" + +static inline bool is_unicode_valid(uint32_t ch) { + + if (ch >= 0x110000) /* End of unicode space */ + return false; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return false; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return false; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return false; + + return true; +} + +static bool is_unicode_control(uint32_t ch) { + + /* + 0 to ' '-1 is the C0 range. + DEL=0x7F, and DEL+1 to 0x9F is C1 range. + '\t' is in C0 range, but more or less harmless and commonly used. + */ + + return (ch < ' ' && ch != '\t' && ch != '\n') || + (0x7F <= ch && ch <= 0x9F); +} + +/* 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 */ +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; +} + +bool utf8_is_printable(const char* str, size_t length) { + const uint8_t *p; + + assert(str); + + for (p = (const uint8_t*) str; length;) { + int encoded_len = utf8_encoded_valid_unichar((const char *)p); + int val = utf8_encoded_to_unichar((const char*)p); + + if (encoded_len < 0 || val < 0 || is_unicode_control(val)) + return false; + + length -= encoded_len; + p += encoded_len; + } + + return true; +} + +char *ascii_is_valid(const char *str) { + const char *p; + + assert(str); + + for (p = str; *p; p++) + if ((unsigned char) *p >= 128) + return NULL; + + return (char*) str; +} + +char *utf16_to_utf8(const void *s, size_t length) { + char *r; + const uint8_t *f; + uint8_t *t; + + r = new(char, (length*3+1)/2 + 1); + if (!r) + return NULL; + + t = (uint8_t*) r; + + for (f = s; f < (const uint8_t*) s + length; f += 2) { + uint16_t c; + + c = (f[1] << 8) | f[0]; + + if (c == 0) { + *t = 0; + return r; + } else if (c < 0x80) { + *(t++) = (uint8_t) c; + } else if (c < 0x800) { + *(t++) = (uint8_t) (0xc0 | (c >> 6)); + *(t++) = (uint8_t) (0x80 | (c & 0x3f)); + } else { + *(t++) = (uint8_t) (0xe0 | (c >> 12)); + *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); + *(t++) = (uint8_t) (0x80 | (c & 0x3f)); + } + } + + *t = 0; + + return r; +} + +/* 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; +} + +/* validate one encoded unicode char and return its length */ +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 (!is_unicode_valid(unichar)) + return -1; + + return len; +} diff --git a/src/shared/utf8.h b/src/shared/utf8.h new file mode 100644 index 0000000000..9d09153c1c --- /dev/null +++ b/src/shared/utf8.h @@ -0,0 +1,31 @@ +/*** + This file is part of eudev, forked from systemd + + Copyright 2012 Lennart Poettering + + 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 "macro.h" + +char *ascii_is_valid(const char *s) _pure_; + +bool utf8_is_printable(const char* str, size_t length) _pure_; + +char *utf16_to_utf8(const void *s, size_t length); + +int utf8_encoded_valid_unichar(const char *str); +int utf8_encoded_to_unichar(const char *str); diff --git a/src/shared/util.c b/src/shared/util.c new file mode 100644 index 0000000000..5ff767b6a7 --- /dev/null +++ b/src/shared/util.c @@ -0,0 +1,1187 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "ioprio.h" +#include "missing.h" +#include "log.h" +#include "strv.h" +#include "label.h" +#include "path-util.h" +#include "exit-status.h" +#include "hashmap.h" +#include "fileio.h" + +int saved_argc = 0; +char **saved_argv = NULL; + +static volatile unsigned cached_columns = 0; +static volatile unsigned cached_lines = 0; + +size_t page_size(void) { + static thread_local size_t pgsz = 0; + long r; + + if (_likely_(pgsz > 0)) + return pgsz; + + r = sysconf(_SC_PAGESIZE); + assert(r > 0); + + pgsz = (size_t) r; + return pgsz; +} + +bool streq_ptr(const char *a, const char *b) { + + /* Like streq(), but tries to make sense of NULL pointers */ + + if (a && b) + return streq(a, b); + + if (!a && !b) + return true; + + return false; +} + +char* endswith(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +int close_nointr(int fd) { + int r; + + assert(fd >= 0); + r = close(fd); + + /* Just ignore EINTR; a retry loop is the wrong + * thing to do on Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (_unlikely_(r < 0 && errno == EINTR)) + return 0; + else if (r >= 0) + return r; + else + return -errno; +} + +void close_nointr_nofail(int fd) { + PROTECT_ERRNO; + + /* like close_nointr() but cannot fail, and guarantees errno + * is unchanged */ + + assert_se(close_nointr(fd) == 0); +} + +int safe_close(int fd) { + + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ + + if (fd >= 0) { + PROTECT_ERRNO; + + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ + + assert_se(close_nointr(fd) != -EBADF); + } + + return -1; +} + +int unlink_noerrno(const char *path) { + PROTECT_ERRNO; + int r; + + r = unlink(path); + if (r < 0) + return -errno; + + return 0; +} + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +int safe_atoi(const char *s, int *ret_i) { + char *x = NULL; + long l; + + assert(s); + assert(ret_i); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((long) (int) l != l) + return -ERANGE; + + *ret_i = (int) l; + return 0; +} + +int safe_atollu(const char *s, long long unsigned *ret_llu) { + char *x = NULL; + unsigned long long l; + + assert(s); + assert(ret_llu); + + errno = 0; + l = strtoull(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_llu = l; + return 0; +} + +int safe_atolli(const char *s, long long int *ret_lli) { + char *x = NULL; + long long l; + + assert(s); + assert(ret_lli); + + errno = 0; + l = strtoll(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_lli = l; + return 0; +} + +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + size_t n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + break; + } + /* if s ends in \, return index of previous char */ + return n - escaped; +} + +/* Split a string into words. */ +const char* split(const char **state, size_t *l, const char *separator, bool quoted) { + const char *current; + + current = *state; + + if (!*current) { + assert(**state == '\0'); + return NULL; + } + + current += strspn(current, separator); + if (!*current) { + *state = current; + return NULL; + } + + if (quoted && strchr("\'\"", *current)) { + char quotechars[2] = {*current, '\0'}; + + *l = strcspn_escaped(current + 1, quotechars); + if (current[*l + 1] == '\0' || + (current[*l + 2] && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end*/ + *state = current; + return NULL; + } + assert(current[*l + 1] == quotechars[0]); + *state = current++ + *l + 2; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + *state = current + *l; + } else { + *l = strcspn(current, separator); + *state = current + *l; + } + + return current; +} + + +char *truncate_nl(char *s) { + assert(s); + + s[strcspn(s, NEWLINE)] = 0; + return s; +} + +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; + char *r; + + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + + assert(s); + assert(suffix); + + a = strlen(s); + if (b > ((size_t) -1) - a) + return NULL; + + r = new(char, a+b+1); + if (!r) + return NULL; + + memcpy(r, s, a); + memcpy(r+a, suffix, b); + r[a+b] = 0; + + return r; +} + +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + +char hexchar(int x) { + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +char octchar(int x) { + return '0' + (x & 7); +} + +char *cescape(const char *s) { + char *r, *t; + const char *f; + + assert(s); + + /* Does C style string escaping. */ + + r = new(char, strlen(s)*4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) + + switch (*f) { + + case '\a': + *(t++) = '\\'; + *(t++) = 'a'; + break; + case '\b': + *(t++) = '\\'; + *(t++) = 'b'; + break; + case '\f': + *(t++) = '\\'; + *(t++) = 'f'; + break; + case '\n': + *(t++) = '\\'; + *(t++) = 'n'; + break; + case '\r': + *(t++) = '\\'; + *(t++) = 'r'; + break; + case '\t': + *(t++) = '\\'; + *(t++) = 't'; + break; + case '\v': + *(t++) = '\\'; + *(t++) = 'v'; + break; + case '\\': + *(t++) = '\\'; + *(t++) = '\\'; + break; + case '"': + *(t++) = '\\'; + *(t++) = '"'; + break; + case '\'': + *(t++) = '\\'; + *(t++) = '\''; + break; + + default: + /* For special chars we prefer octal over + * hexadecimal encoding, simply because glib's + * g_strescape() does the same */ + if ((*f < ' ') || (*f >= 127)) { + *(t++) = '\\'; + *(t++) = octchar((unsigned char) *f >> 6); + *(t++) = octchar((unsigned char) *f >> 3); + *(t++) = octchar((unsigned char) *f); + } else + *(t++) = *f; + break; + } + + *t = 0; + + return r; +} + +char *xescape(const char *s, const char *bad) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and all special + * chars, in \xFF style escaping. May be reversed with + * cunescape. */ + + r = new(char, strlen(s) * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) { + + if ((*f < ' ') || (*f >= 127) || + (*f == '\\') || strchr(bad, *f)) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(*f >> 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +_pure_ static bool ignore_file_allow_backup(const char *filename) { + assert(filename); + + return + filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, ".rpmnew") || + endswith(filename, ".rpmsave") || + endswith(filename, ".rpmorig") || + endswith(filename, ".dpkg-old") || + endswith(filename, ".dpkg-new") || + endswith(filename, ".swp"); +} + +bool ignore_file(const char *filename) { + assert(filename); + + if (endswith(filename, "~")) + return false; + + 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; + + /* + * If a TTY is in the process of being closed opening it might + * cause EIO. This is horribly awful, but unlikely to be + * changed in the kernel. Hence we work around this problem by + * retrying a couple of times. + * + * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 + */ + + assert(!(mode & O_CREAT)); + + for (;;) { + fd = open(name, mode, 0); + if (fd >= 0) + break; + + if (errno != EIO) + return -errno; + + /* Max 1s in total */ + if (c >= 20) + return -errno; + + usleep(50 * USEC_PER_MSEC); + c++; + } + + if (fd < 0) + return -errno; + + r = isatty(fd); + if (r < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (!r) { + close_nointr_nofail(fd); + return -ENOTTY; + } + + return fd; +} + +_pure_ static int is_temporary_fs(struct statfs *s) { + assert(s); + + 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) { + assert(path); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != (mode_t) -1) + if (chmod(path, mode) < 0) + return -errno; + + if (uid != (uid_t) -1 || gid != (gid_t) -1) + if (chown(path, uid, gid) < 0) + return -errno; + + return 0; +} + +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + return true; + + return false; +} + +int null_or_empty_path(const char *fn) { + struct stat st; + + assert(fn); + + if (stat(fn, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int null_or_empty_fd(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { + assert(de); + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + if (ignore_file_allow_backup(de->d_name)) + return false; + + return endswith(de->d_name, suffix); +} + +bool nulstr_contains(const char*nulstr, const char *needle) { + const char *i; + + if (!nulstr) + return false; + + NULSTR_FOREACH(i, nulstr) + if (streq(i, needle)) + return true; + + return false; +} + +int execute_command(const char *command, char *const argv[]) +{ + + pid_t pid; + int status; + + if ((status = access(command, X_OK)) != 0) + return status; + + if ((pid = fork()) < 0) { + log_error("Failed to fork: %m"); + return pid; + } + + if (pid == 0) { + + execvp(command, argv); + + log_error("Failed to execute %s: %m", command); + _exit(EXIT_FAILURE); + } + else while (1) + { + siginfo_t si; + + int r = waitid(P_PID, pid, &si, WEXITED); + + if (!is_clean_exit(si.si_code, si.si_status, NULL)) { + if (si.si_code == CLD_EXITED) + log_error("%s exited with exit status %i.", command, si.si_status); + else + log_error("%s terminated by signal %s.", command, signal_to_string(si.si_status)); + } else + log_debug("%s exited successfully.", command); + + return si.si_status; + + } +} + +int flush_fd(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + + for (;;) { + char buf[LINE_MAX]; + ssize_t l; + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + l = read(fd, buf, sizeof(buf)); + if (l < 0) { + + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } else if (l == 0) + return 0; + } +} + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { + FILE *f; + char *t; + const char *fn; + size_t k; + int fd; + + assert(path); + assert(_f); + assert(_temp_path); + + t = new(char, strlen(path) + 1 + 6 + 1); + if (!t) + return -ENOMEM; + + fn = path_get_file_name(path); + k = fn-path; + memcpy(t, path, k); + t[k] = '.'; + stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); + +#if HAVE_DECL_MKOSTEMP + fd = mkostemp(t, O_WRONLY|O_CLOEXEC); +#else + fd = mkstemp(t); + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif + if (fd < 0) { + free(t); + return -errno; + } + + f = fdopen(fd, "we"); + if (!f) { + unlink(t); + free(t); + return -errno; + } + + *_f = f; + *_temp_path = t; + + 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; + char *r, *p; + + va_start(ap, x); + + if (x) { + l = strlen(x); + + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + } else + l = 0; + + va_end(ap); + + r = new(char, l+1); + if (!r) + return NULL; + + if (x) { + p = stpcpy(r, x); + + va_start(ap, x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + + va_end(ap); + } else + r[0] = 0; + + return r; +} + +bool is_main_thread(void) { + static __thread int cached = 0; + + if (_unlikely_(cached == 0)) + cached = getpid() == gettid() ? 1 : -1; + + return cached > 0; +} + +static const char *const ioprio_class_table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); + +static const char *const sigchld_code_table[] = { + [CLD_EXITED] = "exited", + [CLD_KILLED] = "killed", + [CLD_DUMPED] = "dumped", + [CLD_TRAPPED] = "trapped", + [CLD_STOPPED] = "stopped", + [CLD_CONTINUED] = "continued", +}; + +DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); + +static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { + [LOG_FAC(LOG_KERN)] = "kern", + [LOG_FAC(LOG_USER)] = "user", + [LOG_FAC(LOG_MAIL)] = "mail", + [LOG_FAC(LOG_DAEMON)] = "daemon", + [LOG_FAC(LOG_AUTH)] = "auth", + [LOG_FAC(LOG_SYSLOG)] = "syslog", + [LOG_FAC(LOG_LPR)] = "lpr", + [LOG_FAC(LOG_NEWS)] = "news", + [LOG_FAC(LOG_UUCP)] = "uucp", + [LOG_FAC(LOG_CRON)] = "cron", + [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", + [LOG_FAC(LOG_FTP)] = "ftp", + [LOG_FAC(LOG_LOCAL0)] = "local0", + [LOG_FAC(LOG_LOCAL1)] = "local1", + [LOG_FAC(LOG_LOCAL2)] = "local2", + [LOG_FAC(LOG_LOCAL3)] = "local3", + [LOG_FAC(LOG_LOCAL4)] = "local4", + [LOG_FAC(LOG_LOCAL5)] = "local5", + [LOG_FAC(LOG_LOCAL6)] = "local6", + [LOG_FAC(LOG_LOCAL7)] = "local7" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); + +static const char *const log_level_table[] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); + +static const char* const sched_policy_table[] = { + [SCHED_OTHER] = "other", + [SCHED_BATCH] = "batch", + [SCHED_IDLE] = "idle", + [SCHED_FIFO] = "fifo", + [SCHED_RR] = "rr" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); + +static const char* const rlimit_table[] = { + [RLIMIT_CPU] = "LimitCPU", + [RLIMIT_FSIZE] = "LimitFSIZE", + [RLIMIT_DATA] = "LimitDATA", + [RLIMIT_STACK] = "LimitSTACK", + [RLIMIT_CORE] = "LimitCORE", + [RLIMIT_RSS] = "LimitRSS", + [RLIMIT_NOFILE] = "LimitNOFILE", + [RLIMIT_AS] = "LimitAS", + [RLIMIT_NPROC] = "LimitNPROC", + [RLIMIT_MEMLOCK] = "LimitMEMLOCK", + [RLIMIT_LOCKS] = "LimitLOCKS", + [RLIMIT_SIGPENDING] = "LimitSIGPENDING", + [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", + [RLIMIT_NICE] = "LimitNICE", + [RLIMIT_RTPRIO] = "LimitRTPRIO", + [RLIMIT_RTTIME] = "LimitRTTIME" +}; + +DEFINE_STRING_TABLE_LOOKUP(rlimit, int); + +static const char* const ip_tos_table[] = { + [IPTOS_LOWDELAY] = "low-delay", + [IPTOS_THROUGHPUT] = "throughput", + [IPTOS_RELIABILITY] = "reliability", + [IPTOS_LOWCOST] = "low-cost", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); + +static const char *const __signal_table[] = { + [SIGHUP] = "HUP", + [SIGINT] = "INT", + [SIGQUIT] = "QUIT", + [SIGILL] = "ILL", + [SIGTRAP] = "TRAP", + [SIGABRT] = "ABRT", + [SIGBUS] = "BUS", + [SIGFPE] = "FPE", + [SIGKILL] = "KILL", + [SIGUSR1] = "USR1", + [SIGSEGV] = "SEGV", + [SIGUSR2] = "USR2", + [SIGPIPE] = "PIPE", + [SIGALRM] = "ALRM", + [SIGTERM] = "TERM", +#ifdef SIGSTKFLT + [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ +#endif + [SIGCHLD] = "CHLD", + [SIGCONT] = "CONT", + [SIGSTOP] = "STOP", + [SIGTSTP] = "TSTP", + [SIGTTIN] = "TTIN", + [SIGTTOU] = "TTOU", + [SIGURG] = "URG", + [SIGXCPU] = "XCPU", + [SIGXFSZ] = "XFSZ", + [SIGVTALRM] = "VTALRM", + [SIGPROF] = "PROF", + [SIGWINCH] = "WINCH", + [SIGIO] = "IO", + [SIGPWR] = "PWR", + [SIGSYS] = "SYS" +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); + +const char *signal_to_string(int signo) { + static __thread char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; + const char *name; + + name = __signal_to_string(signo); + if (name) + return name; + + if (signo >= SIGRTMIN && signo <= SIGRTMAX) + snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); + else + snprintf(buf, sizeof(buf), "%d", signo); + + return buf; +} + +int fd_inc_sndbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); + + r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); + if (r >= 0 && + l == sizeof(value) && + (size_t) value >= n*2) + return 0; + + value = (int) n; + r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)); + if (r < 0) + return -errno; + + return 1; +} + +bool in_initrd(void) { + static __thread int saved = -1; + struct statfs s; + + if (saved >= 0) + return saved; + + /* We make two checks here: + * + * 1. the flag file /etc/initrd-release must exist + * 2. the root file system must be a memory file system + * + * The second check is extra paranoia, since misdetecting an + * initrd can have bad bad consequences due the initrd + * emptying when transititioning to the main systemd. + */ + + saved = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); + + return saved; +} + +/* hey glibc, APIs with callbacks without a user pointer are so useless */ +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), void *arg) { + size_t l, u, idx; + const void *p; + int comparison; + + l = 0; + u = nmemb; + while (l < u) { + idx = (l + u) / 2; + p = (void *)(((const char *) base) + (idx * size)); + comparison = compar(key, p, arg); + if (comparison < 0) + u = idx; + else if (comparison > 0) + l = idx + 1; + else + return (void *)p; + } + return NULL; +} + +int proc_cmdline(char **ret) { + int r; + + /* disable containers for now + if (detect_container(NULL) > 0) { + char *buf, *p; + size_t sz = 0; + + r = read_full_file("/proc/1/cmdline", &buf, &sz); + if (r < 0) + return r; + + for (p = buf; p + 1 < buf + sz; p++) + if (*p == 0) + *p = ' '; + + *p = 0; + *ret = buf; + return 1; + } + */ + + r = read_one_line_file("/proc/cmdline", ret); + if (r < 0) + return r; + + return 1; +} + +int getpeercred(int fd, struct ucred *ucred) { + socklen_t n = sizeof(struct ucred); + struct ucred u; + int r; + + assert(fd >= 0); + assert(ucred); + + r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); + if (r < 0) + return -errno; + + if (n != sizeof(struct ucred)) + return -EIO; + + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + + *ucred = u; + return 0; +} diff --git a/src/shared/util.h b/src/shared/util.h new file mode 100644 index 0000000000..5e699ca5a8 --- /dev/null +++ b/src/shared/util.h @@ -0,0 +1,353 @@ +/*** + This file is part of eudev, forked from systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "missing.h" +#include "config.h" + +#if SIZEOF_PID_T == 4 +# define PID_FMT "%" PRIu32 +#elif SIZEOF_PID_T == 2 +# define PID_FMT "%" PRIu16 +#else +# error Unknown pid_t size +#endif + +#if SIZEOF_UID_T == 4 +# define UID_FMT "%" PRIu32 +#elif SIZEOF_UID_T == 2 +# define UID_FMT "%" PRIu16 +#else +# error Unknown uid_t size +#endif + +#if SIZEOF_GID_T == 4 +# define GID_FMT "%" PRIu32 +#elif SIZEOF_GID_T == 2 +# define GID_FMT "%" PRIu16 +#else +# error Unknown gid_t size +#endif + +#if SIZEOF_TIME_T == 8 +# define PRI_TIME PRIu64 +#elif SIZEOF_GID_T == 4 +# define PRI_TIME PRIu32 +#else +# error Unknown time_t size +#endif + +#if SIZEOF_RLIM_T == 8 +# define RLIM_FMT "%" PRIu64 +#elif SIZEOF_RLIM_T == 4 +# define RLIM_FMT "%" PRIu32 +#else +# error Unknown rlim_t size +#endif + +#include "macro.h" +#include "missing.h" + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" + +#define FORMAT_BYTES_MAX 8 + +#define ANSI_HIGHLIGHT_ON "\x1B[1;39m" +#define ANSI_RED_ON "\x1B[31m" +#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m" +#define ANSI_GREEN_ON "\x1B[32m" +#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" +#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m" +#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m" +#define ANSI_HIGHLIGHT_OFF "\x1B[0m" +#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" + +size_t page_size(void); +#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +bool streq_ptr(const char *a, const char *b) _pure_; + +#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) + +#define new0(t, n) ((t*) calloc((n), sizeof(t))) +#define malloc0(n) (calloc((n), 1)) + +static inline bool isempty(const char *p) { + return !p || !p[0]; +} + +static inline const char *startswith(const char *s, const char *prefix) { + if (strncmp(s, prefix, strlen(prefix)) == 0) + return s + strlen(prefix); + return NULL; +} + +char *endswith(const char *s, const char *postfix) _pure_; + +int close_nointr(int fd); +int safe_close(int fd); + +void close_nointr_nofail(int fd); + +int safe_atou(const char *s, unsigned *ret_u); +int safe_atoi(const char *s, int *ret_i); + +int safe_atollu(const char *s, unsigned long long *ret_u); +int safe_atolli(const char *s, long long int *ret_i); + +const char* split(const char **state, size_t *l, const char *separator, bool quoted); + +#define FOREACH_WORD_QUOTED(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, true, state) + +#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ + for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) + +char *strappend(const char *s, const char *suffix); +char *strnappend(const char *s, const char *suffix, size_t length); + +char *truncate_nl(char *s); + +char octchar(int x) _const_; +char hexchar(int x) _const_; + +char *cescape(const char *s); +char *xescape(const char *s, const char *bad); + +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; + +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) { \ + if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ + return NULL; \ + return name##_table[i]; \ + } \ + scope type name##_from_string(const char *s) { \ + type i; \ + assert(s); \ + for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ + if (name##_table[i] && \ + streq(name##_table[i], s)) \ + return i; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + int name##_to_string_alloc(type i, char **str) { \ + char *s; \ + int r; \ + if (i < 0 || i > max) \ + return -ERANGE; \ + if (i < (type) ELEMENTSOF(name##_table)) { \ + s = strdup(name##_table[i]); \ + if (!s) \ + return log_oom(); \ + } else { \ + r = asprintf(&s, "%u", i); \ + if (r < 0) \ + return log_oom(); \ + } \ + *str = s; \ + return 0; \ + } \ + type name##_from_string(const char *s) { \ + type i; \ + unsigned u = 0; \ + assert(s); \ + for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ + if (name##_table[i] && \ + streq(name##_table[i], s)) \ + return i; \ + if (safe_atou(s, &u) >= 0 && u <= max) \ + return (type) u; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +int open_terminal(const char *name, int mode); + +int flush_fd(int fd); + +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_; +int null_or_empty_path(const char *fn); +int null_or_empty_fd(int fd); + +int execute_command(const char *command, char *const argv[]); + +bool nulstr_contains(const char*nulstr, const char *needle); + +char *strjoin(const char *x, ...) _sentinel_; + +bool is_main_thread(void); + +#define NULSTR_FOREACH(i, l) \ + for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) + +#define NULSTR_FOREACH_PAIR(i, j, l) \ + for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) + +int ioprio_class_to_string_alloc(int i, char **s); +int ioprio_class_from_string(const char *s); + +const char *sigchld_code_to_string(int i) _const_; +int sigchld_code_from_string(const char *s) _pure_; + +int log_facility_unshifted_to_string_alloc(int i, char **s); +int log_facility_unshifted_from_string(const char *s); + +int log_level_to_string_alloc(int i, char **s); +int log_level_from_string(const char *s); + +int sched_policy_to_string_alloc(int i, char **s); +int sched_policy_from_string(const char *s); + +const char *rlimit_to_string(int i) _const_; +int rlimit_from_string(const char *s) _pure_; + +int ip_tos_to_string_alloc(int i, char **s); +int ip_tos_from_string(const char *s); + +const char *signal_to_string(int i) _const_; + +extern int saved_argc; +extern char **saved_argv; + +int fd_inc_sndbuf(int fd, size_t n); + +bool in_initrd(void); + +static inline void freep(void *p) { + free(*(void**) p); +} + +#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ + static inline void func##p(type *p) { \ + if (*p) \ + func(*p); \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +static inline void fclosep(FILE **f) { + if (*f) + fclose(*f); +} + +static inline void closep(int *fd) { + if (*fd >= 0) + close_nointr_nofail(*fd); +} + +static inline void closedirp(DIR **d) { + if (*d) + closedir(*d); +} + +#define _cleanup_free_ _cleanup_(freep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_closedir_ _cleanup_(closedirp) + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { + if (_unlikely_(b == 0 || a > ((size_t) -1) / b)) + return NULL; + + return malloc(a * b); +} + +/** + * Check if a string contains any glob patterns. + */ +_pure_ static inline bool string_is_glob(const char *p) { + return !!strpbrk(p, GLOB_CHARS); +} + +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), + void *arg); + +#define FOREACH_LINE(line, f, on_error) \ + for (;;) \ + if (!fgets(line, sizeof(line), f)) { \ + if (ferror(f)) { \ + on_error; \ + } \ + break; \ + } else + +static inline void _reset_errno_(int *saved_errno) { + errno = *saved_errno; +} + +#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno + +int unlink_noerrno(const char *path); +static inline void qsort_safe(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) { + if (nmemb) { + assert(base); + qsort(base, nmemb, size, compar); + } +} + +int proc_cmdline(char **ret); +int getpeercred(int fd, struct ucred *ucred); + +union file_handle_union { + struct file_handle handle; + char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; +}; diff --git a/src/udev/Makefile.am b/src/udev/Makefile.am index 8722524e67..638e2d5678 100644 --- a/src/udev/Makefile.am +++ b/src/udev/Makefile.am @@ -10,6 +10,7 @@ AM_CPPFLAGS = \ -DUDEV_RULES_DIR=\"$(udevrulesdir)\" \ -DUDEV_LIBEXEC_DIR=\"$(udevlibexecdir)\" \ -DUDEV_VERSION=\"$(UDEV_VERSION)\" \ + -I $(top_srcdir)/src/shared \ -I $(top_srcdir)/src/libudev bin_PROGRAMS = \ @@ -54,24 +55,13 @@ libudev_core_la_SOURCES = \ udev-builtin-input_id.c \ udev-builtin-net_id.c \ udev-builtin-path_id.c \ - udev-builtin-usb_id.c \ - dev-setup.c \ - label.c \ - mkdir.c \ - smack-util.c + udev-builtin-usb_id.c if ENABLE_FIRMWARE libudev_core_la_SOURCES += \ udev-builtin-firmware.c endif -noinst_HEADERS = \ - dev-setup.h \ - label.h \ - mkdir.h \ - smack-util.h \ - udev-util.h - include_HEADERS = \ udev.h @@ -80,6 +70,7 @@ libudev_core_la_CFLAGS = \ $(BLKID_CFLAGS) libudev_core_la_LIBADD = \ + $(top_builddir)/src/shared/libudev_shared.la \ $(top_builddir)/src/libudev/libudev-private.la \ $(BLKID_LIBS) \ $(SELINUX_LIBS) @@ -92,15 +83,12 @@ endif if HAVE_MODULES libudev_core_la_SOURCES += \ udev-builtin-kmod.c - if HAVE_LIBKMOD libudev_core_la_CFLAGS += $(KMOD_CFLAGS) libudev_core_la_LIBADD += $(KMOD_LIBS) endif endif - - libudev_core_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -DFIRMWARE_PATH="$(FIRMWARE_PATH)" diff --git a/src/udev/dev-setup.c b/src/udev/dev-setup.c deleted file mode 100644 index 1a565d5470..0000000000 --- a/src/udev/dev-setup.c +++ /dev/null @@ -1,84 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 -#include -#include -#include -#include - -#include "dev-setup.h" -#include "log.h" -#include "macro.h" -#include "util.h" -#include "label.h" - -static int symlink_and_label(const char *old_path, const char *new_path) { - int r; - - assert(old_path); - assert(new_path); - - r = label_context_set(new_path, S_IFLNK); - if (r < 0) - return r; - - if (symlink(old_path, new_path) < 0) - r = -errno; - - label_context_clear(); - - return r; -} - -int dev_setup(const char *prefix) { - const char *j, *k; - - static const char symlinks[] = - "-/proc/kcore\0" "/dev/core\0" - "/proc/self/fd\0" "/dev/fd\0" - "/proc/self/fd/0\0" "/dev/stdin\0" - "/proc/self/fd/1\0" "/dev/stdout\0" - "/proc/self/fd/2\0" "/dev/stderr\0"; - - NULSTR_FOREACH_PAIR(j, k, symlinks) { - if (j[0] == '-') { - j++; - - if (access(j, F_OK) < 0) - continue; - } - - if (prefix) { - _cleanup_free_ char *link_name = NULL; - - link_name = strjoin(prefix, "/", k, NULL); - if (!link_name) - return -ENOMEM; - - symlink_and_label(j, link_name); - } else - symlink_and_label(j, k); - } - - return 0; -} diff --git a/src/udev/dev-setup.h b/src/udev/dev-setup.h deleted file mode 100644 index d41b6eefba..0000000000 --- a/src/udev/dev-setup.h +++ /dev/null @@ -1,24 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 . -***/ - -int dev_setup(const char *pathprefix); diff --git a/src/udev/label.c b/src/udev/label.c deleted file mode 100644 index dca2a21228..0000000000 --- a/src/udev/label.c +++ /dev/null @@ -1,247 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include - -#include "label.h" -#include "util.h" -#include "path-util.h" - -#ifdef HAVE_SELINUX -#include -#include -#include - -static struct selabel_handle *label_hnd = NULL; -static int use_selinux_cached = -1; - -bool use_selinux(void) { - if (use_selinux_cached < 0) - use_selinux_cached = is_selinux_enabled() > 0; - - return use_selinux_cached; -} -#endif - -int label_init(const char *prefix) { - int r = 0; - -#ifdef HAVE_SELINUX - usec_t before_timestamp, after_timestamp; - struct mallinfo before_mallinfo, after_mallinfo; - - if (!use_selinux()) - return 0; - - if (label_hnd) - return 0; - - before_mallinfo = mallinfo(); - before_timestamp = now(CLOCK_MONOTONIC); - - if (prefix) { - struct selinux_opt options[] = { - { .type = SELABEL_OPT_SUBSET, .value = prefix }, - }; - - label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); - } else - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - - if (!label_hnd) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to initialize SELinux context: %m"); - r = security_getenforce() == 1 ? -errno : 0; - } else { - char timespan[FORMAT_TIMESPAN_MAX]; - int l; - - after_timestamp = now(CLOCK_MONOTONIC); - after_mallinfo = mallinfo(); - - l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0; - - log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.", - format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0), - (l+1023)/1024); - } -#endif - - return r; -} - -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { - int r = 0; - -#ifdef HAVE_SELINUX - struct stat st; - security_context_t fcon; - - if (!use_selinux() || !label_hnd) - return 0; - - r = lstat(path, &st); - if (r == 0) { - r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); - - /* If there's no label to set, then exit without warning */ - if (r < 0 && errno == ENOENT) - return 0; - - if (r == 0) { - r = lsetfilecon(path, fcon); - freecon(fcon); - - /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == ENOTSUP) - return 0; - } - } - - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) - return 0; - - if (ignore_erofs && errno == EROFS) - return 0; - - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Unable to fix label of %s: %m", path); - r = security_getenforce() == 1 ? -errno : 0; - } -#endif - - return r; -} - -void label_finish(void) { - -#ifdef HAVE_SELINUX - if (use_selinux() && label_hnd) - selabel_close(label_hnd); -#endif -} - -int label_context_set(const char *path, mode_t mode) { - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t filecon = NULL; - - if (!use_selinux() || !label_hnd) - return 0; - - r = selabel_lookup_raw(label_hnd, &filecon, path, mode); - if (r < 0 && errno != ENOENT) - r = -errno; - else if (r == 0) { - r = setfscreatecon(filecon); - if (r < 0) { - log_error("Failed to set SELinux file context on %s: %m", path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif - - return r; -} - -void label_context_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setfscreatecon(NULL); -#endif -} - -int label_mkdir(const char *path, mode_t mode, bool apply) { - - /* Creates a directory and labels it according to the SELinux policy */ -#ifdef HAVE_SELINUX - int r; - security_context_t fcon = NULL; - - if (!apply || !use_selinux() || !label_hnd) - goto skipped; - - if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR); - else { - char *newpath; - - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; - - r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR); - free(newpath); - } - - if (r == 0) - r = setfscreatecon(fcon); - - if (r < 0 && errno != ENOENT) { - log_error("Failed to set security context %s for %s: %m", fcon, path); - - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } - } - - r = mkdir(path, mode); - if (r < 0) - r = -errno; - -finish: - setfscreatecon(NULL); - freecon(fcon); - - return r; - -skipped: -#endif - return mkdir(path, mode) < 0 ? -errno : 0; -} - -int label_apply(const char *path, const char *label) { - int r = 0; - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return 0; - - r = setfilecon(path, (char *)label); -#endif - return r; -} diff --git a/src/udev/label.h b/src/udev/label.h deleted file mode 100644 index a8dbcdc8b7..0000000000 --- a/src/udev/label.h +++ /dev/null @@ -1,38 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include - -int label_init(const char *prefix); -void label_finish(void); - -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs); - -int label_context_set(const char *path, mode_t mode); -void label_context_clear(void); - -int label_mkdir(const char *path, mode_t mode, bool apply); - -int label_apply(const char *path, const char *label); diff --git a/src/udev/mkdir.c b/src/udev/mkdir.c deleted file mode 100644 index 770ee994c4..0000000000 --- a/src/udev/mkdir.c +++ /dev/null @@ -1,157 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 -#include -#include -#include -#include -#include - -#include "label.h" -#include "util.h" -#include "mkdir.h" - -static int is_dir(const char* path) { - struct stat st; - - if (stat(path, &st) < 0) - return -errno; - - return S_ISDIR(st.st_mode); -} - - -char* path_startswith(const char *path, const char *prefix) { - assert(path); - assert(prefix); - - if ((path[0] == '/') != (prefix[0] == '/')) - return NULL; - - for (;;) { - size_t a, b; - - path += strspn(path, "/"); - prefix += strspn(prefix, "/"); - - if (*prefix == 0) - return (char*) path; - - if (*path == 0) - return NULL; - - a = strcspn(path, "/"); - b = strcspn(prefix, "/"); - - if (a != b) - return NULL; - - if (memcmp(path, prefix, a) != 0) - return NULL; - - path += a; - prefix += b; - } -} - -static int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, bool apply) { - const char *p, *e; - int r; - - assert(path); - - if (prefix && !path_startswith(path, prefix)) - return -ENOTDIR; - - /* return immediately if directory exists */ - e = strrchr(path, '/'); - if (!e) - return -EINVAL; - - if (e == path) - return 0; - - char buf[PATH_MAX + 1]; - p = buf; - assert(e-path < sizeof(buf)); - memcpy(buf, path, e-path); - buf[e-path] = 0; - - r = is_dir(p); - if (r > 0) - return 0; - if (r == 0) - return -ENOTDIR; - - /* create every parent directory in the path, except the last component */ - p = path + strspn(path, "/"); - for (;;) { - char t[strlen(path) + 1]; - - e = p + strcspn(p, "/"); - p = e + strspn(e, "/"); - - /* Is this the last component? If so, then we're - * done */ - if (*p == 0) - return 0; - - memcpy(t, path, e - path); - t[e-path] = 0; - - if (prefix && path_startswith(prefix, t)) - continue; - - r = label_mkdir(t, mode, apply); - if (r < 0 && errno != EEXIST) - return -errno; - } -} - -int mkdir_parents(const char *path, mode_t mode) { - return mkdir_parents_internal(NULL, path, mode, false); -} - -int mkdir_parents_label(const char *path, mode_t mode) { - return mkdir_parents_internal(NULL, path, mode, true); -} - -static int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, bool apply) { - int r; - - /* Like mkdir -p */ - - r = mkdir_parents_internal(prefix, path, mode, apply); - if (r < 0) - return r; - - r = label_mkdir(path, mode, apply); - if (r < 0 && (errno != EEXIST || is_dir(path) <= 0)) - return -errno; - - return 0; -} - -int mkdir_p(const char *path, mode_t mode) { - return mkdir_p_internal(NULL, path, mode, false); -} diff --git a/src/udev/mkdir.h b/src/udev/mkdir.h deleted file mode 100644 index 24ffa6364c..0000000000 --- a/src/udev/mkdir.h +++ /dev/null @@ -1,29 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomkdirhfoo -#define foomkdirhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 . -***/ - -char* path_startswith(const char *path, const char *prefix) _pure_; -int mkdir_parents(const char *path, mode_t mode); -int mkdir_parents_label(const char *path, mode_t mode); -int mkdir_p(const char *path, mode_t mode); -#endif diff --git a/src/udev/smack-util.c b/src/udev/smack-util.c deleted file mode 100644 index 2711041c7e..0000000000 --- a/src/udev/smack-util.c +++ /dev/null @@ -1,89 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2013 Intel Corporation - - Author: Auke Kok - - 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 -#ifdef HAVE_XATTR -#include -#endif - -#include "smack-util.h" - -bool use_smack(void) { -#ifdef HAVE_SMACK - static int use_smack_cached = -1; - - if (use_smack_cached < 0) - use_smack_cached = access("/sys/fs/smackfs/", F_OK) >= 0; - - return use_smack_cached; -#else - return false; -#endif - -} - -int smack_label_path(const char *path, const char *label) { -#ifdef HAVE_SMACK - if (!use_smack()) - return 0; - - if (label) - return setxattr(path, "security.SMACK64", label, strlen(label), 0); - else - return lremovexattr(path, "security.SMACK64"); -#else - return 0; -#endif -} - -int smack_label_fd(int fd, const char *label) { -#ifdef HAVE_SMACK - if (!use_smack()) - return 0; - - return fsetxattr(fd, "security.SMACK64", label, strlen(label), 0); -#else - return 0; -#endif -} - -int smack_label_ip_out_fd(int fd, const char *label) { -#ifdef HAVE_SMACK - if (!use_smack()) - return 0; - - return fsetxattr(fd, "security.SMACK64IPOUT", label, strlen(label), 0); -#else - return 0; -#endif -} - -int smack_label_ip_in_fd(int fd, const char *label) { -#ifdef HAVE_SMACK - if (!use_smack()) - return 0; - - return fsetxattr(fd, "security.SMACK64IPIN", label, strlen(label), 0); -#else - return 0; -#endif -} diff --git a/src/udev/smack-util.h b/src/udev/smack-util.h deleted file mode 100644 index 88704894e7..0000000000 --- a/src/udev/smack-util.h +++ /dev/null @@ -1,28 +0,0 @@ -/*** - This file is part of eudev, forked from systemd. - - Copyright 2013 Intel Corporation - - Author: Auke Kok - - 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 - -bool use_smack(void); -int smack_label_path(const char *path, const char *label); -int smack_label_fd(int fd, const char *label); -int smack_label_ip_in_fd(int fd, const char *label); -int smack_label_ip_out_fd(int fd, const char *label); diff --git a/src/udev/udev-util.h b/src/udev/udev-util.h deleted file mode 100644 index 5f09ce181f..0000000000 --- a/src/udev/udev-util.h +++ /dev/null @@ -1,42 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew Jędrzejewski-Szmek - - 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 "udev.h" -#include "util.h" - -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref); - -#define _cleanup_udev_unref_ _cleanup_(udev_unrefp) -#define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp) -#define _cleanup_udev_enumerate_unref_ _cleanup_(udev_enumerate_unrefp) -#define _cleanup_udev_event_unref_ _cleanup_(udev_event_unrefp) -#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp) -#define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp) -#define _cleanup_udev_monitor_unref_ _cleanup_(udev_monitor_unrefp) -#define _cleanup_udev_list_cleanup_ _cleanup_(udev_list_cleanup) diff --git a/test/Makefile.am b/test/Makefile.am index f12ee20f04..4b2b431865 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,8 +3,8 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ -DVERSION=\"@VERSION@\" \ - -I $(top_srcdir)/src/libudev \ - -I $(top_srcdir)/src/udev + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/libudev noinst_PROGRAMS = \ test-libudev \ -- cgit v1.2.3-54-g00ecf