summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shared/Makefile.am20
-rw-r--r--src/shared/conf-files.c15
-rw-r--r--src/shared/conf-files.h7
-rw-r--r--src/shared/hashmap.h4
-rw-r--r--src/shared/log.c28
-rw-r--r--src/shared/macro.h13
-rw-r--r--src/shared/missing.h3
-rw-r--r--src/shared/path-util.c83
-rw-r--r--src/shared/path-util.h6
-rw-r--r--src/shared/set.h1
-rw-r--r--src/shared/time-util.c28
-rw-r--r--src/shared/time-util.h3
-rw-r--r--src/shared/util.c339
-rw-r--r--src/shared/util.h32
-rw-r--r--src/shared/virt.c328
-rw-r--r--src/shared/virt.h24
16 files changed, 710 insertions, 224 deletions
diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am
index b4c2000301..4c9f20697b 100644
--- a/src/shared/Makefile.am
+++ b/src/shared/Makefile.am
@@ -7,41 +7,46 @@ libudev_shared_la_SOURCES=\
cgroup-util.c \
conf-files.c \
device-nodes.c \
+ dev-setup.c \
exit-status.c \
fileio.c \
hashmap.c \
+ label.c \
log.c \
+ mkdir.c \
MurmurHash2.c \
path-util.c \
set.c \
siphash24.c \
+ smack-util.c \
strbuf.c \
strv.c \
strxcpyx.c \
time-util.c \
util.c \
utf8.c \
- dev-setup.c \
- label.c \
- mkdir.c \
- smack-util.c
+ virt.c
noinst_HEADERS = \
cgroup-util.h \
conf-files.h \
def.h \
device-nodes.h \
+ dev-setup.h \
exit-status.h \
fileio.h \
hashmap.h \
ioprio.h \
+ label.h \
log.h \
macro.h \
missing.h \
+ mkdir.h \
MurmurHash2.h \
path-util.h \
set.h \
siphash24.h \
+ smack-util.h \
socket-util.h \
sparse-endian.h \
strbuf.h \
@@ -50,11 +55,8 @@ noinst_HEADERS = \
time-util.h \
util.h \
utf8.h \
- dev-setup.h \
- label.h \
- mkdir.h \
- smack-util.h \
- udev-util.h
+ udev-util.h \
+ virt.h
libudev_shared_la_LDFLAGS = \
$(AM_LDFLAGS)
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index dc4f970313..2de4fe0a37 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -39,10 +39,12 @@
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;
+ char *dirpath;
- if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0)
- return -ENOMEM;
+ assert(path);
+ assert(suffix);
+
+ dirpath = strappenda(root ? root : "", path);
dir = opendir(dirpath);
if (!dir) {
@@ -96,7 +98,7 @@ static int base_cmp(const void *a, const void *b) {
}
static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
- Hashmap *fh;
+ _cleanup_hashmap_free_ Hashmap *fh = NULL;
char **files, **p;
int r;
@@ -104,7 +106,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
assert(suffix);
/* This alters the dirs string array */
- if (!path_strv_canonicalize_uniq(dirs))
+ if (!path_strv_resolve_uniq(dirs, root))
return -ENOMEM;
fh = hashmap_new(string_hash_func, string_compare_func);
@@ -114,7 +116,6 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
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",
@@ -123,14 +124,12 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
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;
}
diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h
index a0720dc2cc..b769e56845 100644
--- a/src/shared/conf-files.h
+++ b/src/shared/conf-files.h
@@ -1,7 +1,6 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-#ifndef fooconffileshfoo
-#define fooconffileshfoo
+#pragma once
/***
This file is part of systemd.
@@ -23,6 +22,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs);
+#include "macro.h"
-#endif
+int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs);
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 387c32243e..cfd34750d9 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include "macro.h"
+#include "util.h"
/* Pretty straightforward hash table implementation. As a minor
* optimization a NULL hashmap object will be treated as empty hashmap
@@ -73,3 +74,6 @@ 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))
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
+#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
diff --git a/src/shared/log.c b/src/shared/log.c
index cd496cf6c5..0237d20ff2 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -62,7 +62,7 @@ void log_close_console(void) {
if (getpid() == 1) {
if (console_fd >= 3)
- close_nointr_nofail(console_fd);
+ safe_close(console_fd);
console_fd = -1;
}
@@ -84,12 +84,7 @@ static int log_open_console(void) {
}
void log_close_kmsg(void) {
-
- if (kmsg_fd < 0)
- return;
-
- close_nointr_nofail(kmsg_fd);
- kmsg_fd = -1;
+ kmsg_fd = safe_close(kmsg_fd);
}
static int log_open_kmsg(void) {
@@ -105,16 +100,12 @@ static int log_open_kmsg(void) {
}
void log_close_syslog(void) {
-
- if (syslog_fd < 0)
- return;
-
- close_nointr_nofail(syslog_fd);
- syslog_fd = -1;
+ syslog_fd = safe_close(syslog_fd);
}
static int create_log_socket(int type) {
int fd;
+ struct timeval tv;
fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
if (fd < 0)
@@ -122,6 +113,15 @@ static int create_log_socket(int type) {
fd_inc_sndbuf(fd, SNDBUF_SIZE);
+ /* We need a blocking fd here since we'd otherwise lose
+ messages way too early. However, let's not hang forever in the
+ unlikely case of a deadlock. */
+ if (getpid() == 1)
+ timeval_store(&tv, 10 * USEC_PER_MSEC);
+ else
+ timeval_store(&tv, 10 * USEC_PER_SEC);
+ setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+
return fd;
}
@@ -142,7 +142,7 @@ static int log_open_syslog(void) {
}
if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
- close_nointr_nofail(syslog_fd);
+ safe_close(syslog_fd);
/* Some legacy syslog systems still use stream
* sockets. They really shouldn't. But what can we
diff --git a/src/shared/macro.h b/src/shared/macro.h
index 2deaf04092..3e02d86b5c 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -173,6 +173,19 @@ static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
sizeof(type) <= 2 ? 5 : \
sizeof(type) <= 4 ? 10 : \
sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
+#define IN_SET(x, y, ...) \
+ ({ \
+ const typeof(y) _y = (y); \
+ const typeof(_y) _x = (x); \
+ unsigned _i; \
+ bool _found = false; \
+ for (_i = 0; _i < 1 + sizeof((const typeof(_x)[]) { __VA_ARGS__ })/sizeof(const typeof(_x)); _i++) \
+ if (((const typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \
+ _found = true; \
+ break; \
+ } \
+ _found; \
+ })
/* Define C11 thread_local attribute even on older gcc compiler
* version */
diff --git a/src/shared/missing.h b/src/shared/missing.h
index 471a81120c..3c758956c6 100644
--- a/src/shared/missing.h
+++ b/src/shared/missing.h
@@ -41,6 +41,9 @@
#define RLIMIT_RTTIME 15
#endif
+/* If RLIMIT_RTTIME is not defined, then we cannot use RLIMIT_NLIMITS as is */
+#define _RLIMIT_MAX (RLIMIT_RTTIME+1 > RLIMIT_NLIMITS ? RLIMIT_RTTIME+1 : RLIMIT_NLIMITS)
+
#ifndef BTRFS_IOCTL_MAGIC
#define BTRFS_IOCTL_MAGIC 0x94
#endif
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 41bc20de69..783d130842 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -34,6 +34,7 @@
#include "util.h"
#include "log.h"
#include "strv.h"
+#include "mkdir.h"
#include "path-util.h"
#include "missing.h"
@@ -41,16 +42,8 @@ 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;
+bool is_path(const char *p) {
+ return !!strchr(p, '/');
}
int path_get_parent(const char *path, char **_r) {
@@ -124,7 +117,7 @@ char *path_make_absolute_cwd(const char *p) {
return path_make_absolute(p, cwd);
}
-char **path_strv_canonicalize(char **l) {
+char **path_strv_resolve(char **l, const char *prefix) {
char **s;
unsigned k = 0;
bool enomem = false;
@@ -138,28 +131,63 @@ char **path_strv_canonicalize(char **l) {
STRV_FOREACH(s, l) {
char *t, *u;
+ _cleanup_free_ char *orig = NULL;
- t = path_make_absolute_cwd(*s);
- free(*s);
- *s = NULL;
-
- if (!t) {
- enomem = true;
+ if (!path_is_absolute(*s)) {
+ free(*s);
continue;
}
+ if (prefix) {
+ orig = *s;
+ t = strappend(prefix, orig);
+ if (!t) {
+ enomem = true;
+ continue;
+ }
+ } else
+ t = *s;
+
errno = 0;
- u = realpath(t, 0);
+ u = canonicalize_file_name(t);
if (!u) {
- if (errno == ENOENT)
- u = t;
- else {
+ if (errno == ENOENT) {
+ if (prefix) {
+ u = orig;
+ orig = NULL;
+ free(t);
+ } else
+ u = t;
+ } else {
free(t);
- if (errno == ENOMEM || !errno)
+ if (errno == ENOMEM || errno == 0)
enomem = true;
continue;
}
+ } else if (prefix) {
+ char *x;
+
+ free(t);
+ x = path_startswith(u, prefix);
+ if (x) {
+ /* restore the slash if it was lost */
+ if (!startswith(x, "/"))
+ *(--x) = '/';
+
+ t = strdup(x);
+ free(u);
+ if (!t) {
+ enomem = true;
+ continue;
+ }
+ u = t;
+ } else {
+ /* canonicalized path goes outside of
+ * prefix, keep the original path instead */
+ u = orig;
+ orig = NULL;
+ }
} else
free(t);
@@ -174,11 +202,12 @@ char **path_strv_canonicalize(char **l) {
return l;
}
-char **path_strv_canonicalize_uniq(char **l) {
+char **path_strv_resolve_uniq(char **l, const char *prefix) {
+
if (strv_isempty(l))
return l;
- if (!path_strv_canonicalize(l))
+ if (!path_strv_resolve(l, prefix))
return NULL;
return strv_uniq(l);
@@ -259,7 +288,7 @@ int path_is_mount_point(const char *t, bool allow_symlink) {
};
int mount_id, mount_id_parent;
- char *parent;
+ _cleanup_free_ char *parent = NULL;
struct stat a, b;
int r;
@@ -272,7 +301,7 @@ int path_is_mount_point(const char *t, bool allow_symlink) {
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)
+ if (IN_SET(errno, ENOSYS, EOPNOTSUPP))
/* This kernel or file system does not support
* name_to_handle_at(), hence fallback to the
* traditional stat() logic */
@@ -290,7 +319,6 @@ int path_is_mount_point(const char *t, bool allow_symlink) {
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
@@ -321,7 +349,6 @@ fallback:
return r;
r = lstat(parent, &b);
- free(parent);
if (r < 0)
return -errno;
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index 8e55131093..a62624c1b3 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -19,9 +19,9 @@
#include <stdbool.h>
+#include "macro.h"
#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);
@@ -29,8 +29,8 @@ 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);
+char** path_strv_resolve(char **l, const char *prefix);
+char** path_strv_resolve_uniq(char **l, const char *prefix);
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.h b/src/shared/set.h
index 76383a423a..c6455be7c1 100644
--- a/src/shared/set.h
+++ b/src/shared/set.h
@@ -28,6 +28,7 @@
* for each set use. */
#include "hashmap.h"
+#include "util.h"
typedef struct Set Set;
diff --git a/src/shared/time-util.c b/src/shared/time-util.c
index 6f76e8c19b..3df35b8e24 100644
--- a/src/shared/time-util.c
+++ b/src/shared/time-util.c
@@ -48,6 +48,34 @@ usec_t timespec_load(const struct timespec *ts) {
(usec_t) ts->tv_nsec / NSEC_PER_USEC;
}
+struct timespec *timespec_store(struct timespec *ts, usec_t u) {
+ assert(ts);
+
+ if (u == USEC_INFINITY) {
+ ts->tv_sec = (time_t) -1;
+ ts->tv_nsec = (long) -1;
+ return ts;
+ }
+
+ ts->tv_sec = (time_t) (u / USEC_PER_SEC);
+ ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
+
+ return ts;
+}
+struct timeval *timeval_store(struct timeval *tv, usec_t u) {
+ assert(tv);
+
+ if (u == USEC_INFINITY) {
+ tv->tv_sec = (time_t) -1;
+ tv->tv_usec = (suseconds_t) -1;
+ } else {
+ tv->tv_sec = (time_t) (u / USEC_PER_SEC);
+ tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
+ }
+
+ return tv;
+}
+
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
static const struct {
const char *suffix;
diff --git a/src/shared/time-util.h b/src/shared/time-util.h
index 16ef25b523..58bc59ec4d 100644
--- a/src/shared/time-util.h
+++ b/src/shared/time-util.h
@@ -61,4 +61,7 @@ typedef struct dual_timestamp {
usec_t now(clockid_t clock);
usec_t timespec_load(const struct timespec *ts) _pure_;
+struct timespec *timespec_store(struct timespec *ts, usec_t u);
+
+struct timeval *timeval_store(struct timeval *tv, usec_t u);
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
diff --git a/src/shared/util.c b/src/shared/util.c
index 5ff767b6a7..d551f87e60 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -68,6 +68,7 @@
#include "exit-status.h"
#include "hashmap.h"
#include "fileio.h"
+#include "virt.h"
int saved_argc = 0;
char **saved_argv = NULL;
@@ -128,32 +129,23 @@ int close_nointr(int fd) {
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)
+ if (r >= 0)
return r;
+ else if (errno == EINTR)
+ /*
+ * 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
+ */
+ return 0;
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) {
/*
@@ -490,6 +482,7 @@ _pure_ static bool ignore_file_allow_backup(const char *filename) {
endswith(filename, ".rpmorig") ||
endswith(filename, ".dpkg-old") ||
endswith(filename, ".dpkg-new") ||
+ endswith(filename, ".dpkg-tmp") ||
endswith(filename, ".swp");
}
@@ -497,55 +490,11 @@ bool ignore_file(const char *filename) {
assert(filename);
if (endswith(filename, "~"))
- return false;
+ return true;
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;
@@ -582,18 +531,74 @@ int open_terminal(const char *name, int mode) {
r = isatty(fd);
if (r < 0) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -errno;
}
if (!r) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -ENOTTY;
}
return fd;
}
+int dev_urandom(void *p, size_t n) {
+ _cleanup_close_ int fd;
+ ssize_t k;
+
+ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return errno == ENOENT ? -ENOSYS : -errno;
+
+ k = loop_read(fd, p, n, true);
+ if (k < 0)
+ return (int) k;
+ if ((size_t) k != n)
+ return -EIO;
+
+ return 0;
+}
+
+void random_bytes(void *p, size_t n) {
+ static bool srand_called = false;
+ uint8_t *q;
+ int r;
+
+ r = dev_urandom(p, n);
+ if (r >= 0)
+ return;
+
+ /* If some idiot made /dev/urandom unavailable to us, he'll
+ * get a PRNG instead. */
+
+ if (!srand_called) {
+ unsigned x = 0;
+
+#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)
+ x ^= *(unsigned*) auxv;
+#endif
+
+ x ^= (unsigned) now(CLOCK_REALTIME);
+ x ^= (unsigned) gettid();
+
+ srand(x);
+ srand_called = true;
+ }
+
+ for (q = p; q < (uint8_t*) p + n; q ++)
+ *q = rand();
+}
+
_pure_ static int is_temporary_fs(struct statfs *s) {
assert(s);
@@ -601,6 +606,41 @@ _pure_ static int is_temporary_fs(struct statfs *s) {
F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
+ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
+ uint8_t *p = buf;
+ ssize_t n = 0;
+
+ assert(fd >= 0);
+ assert(buf);
+
+ while (nbytes > 0) {
+ ssize_t k;
+
+ k = read(fd, p, nbytes);
+ if (k < 0 && errno == EINTR)
+ continue;
+
+ if (k < 0 && errno == EAGAIN && do_poll) {
+
+ /* We knowingly ignore any return value here,
+ * and expect that any error/EOF is reported
+ * via read() */
+
+ fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
+ continue;
+ }
+
+ if (k <= 0)
+ return n > 0 ? n : (k < 0 ? -errno : 0);
+
+ p += k;
+ nbytes -= k;
+ n += k;
+ }
+
+ return n;
+}
+
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
assert(path);
@@ -680,8 +720,7 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
return false;
}
-int execute_command(const char *command, char *const argv[])
-{
+int execute_command(const char *command, char *const argv[]) {
pid_t pid;
int status;
@@ -759,28 +798,20 @@ int flush_fd(int fd) {
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);
+ t = tempfn_xxxxxx(path);
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);
+ fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
#else
- fd = mkstemp(t);
+ fd = mkstemp_safe(t);
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
if (fd < 0) {
@@ -801,55 +832,6 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
return 0;
}
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
- uint8_t *p;
- ssize_t n = 0;
-
- assert(fd >= 0);
- assert(buf);
-
- p = buf;
-
- while (nbytes > 0) {
- ssize_t k;
-
- if ((k = read(fd, p, nbytes)) <= 0) {
-
- if (k < 0 && errno == EINTR)
- continue;
-
- if (k < 0 && errno == EAGAIN && do_poll) {
- struct pollfd pollfd = {
- .fd = fd,
- .events = POLLIN,
- };
-
- if (poll(&pollfd, 1, -1) < 0) {
- if (errno == EINTR)
- continue;
-
- return n > 0 ? n : -errno;
- }
-
- /* We knowingly ignore the revents value here,
- * and expect that any error/EOF is reported
- * via read()/write()
- */
-
- continue;
- }
-
- return n > 0 ? n : (k < 0 ? -errno : 0);
- }
-
- p += k;
- nbytes -= k;
- n += k;
- }
-
- return n;
-}
-
char *strjoin(const char *x, ...) {
va_list ap;
size_t l;
@@ -908,7 +890,7 @@ char *strjoin(const char *x, ...) {
}
bool is_main_thread(void) {
- static __thread int cached = 0;
+ static thread_local int cached = 0;
if (_unlikely_(cached == 0))
cached = getpid() == gettid() ? 1 : -1;
@@ -984,7 +966,7 @@ static const char* const sched_policy_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
-static const char* const rlimit_table[] = {
+static const char* const rlimit_table[_RLIMIT_MAX] = {
[RLIMIT_CPU] = "LimitCPU",
[RLIMIT_FSIZE] = "LimitFSIZE",
[RLIMIT_DATA] = "LimitDATA",
@@ -1053,7 +1035,7 @@ static const char *const __signal_table[] = {
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];
+ static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
const char *name;
name = __signal_to_string(signo);
@@ -1068,26 +1050,46 @@ const char *signal_to_string(int signo) {
return buf;
}
+int fd_wait_for_event(int fd, int event, usec_t t) {
+
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = event,
+ };
+
+ struct timespec ts;
+ int r;
+
+ r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
+ if (r < 0)
+ return -errno;
+
+ if (r == 0)
+ return 0;
+
+ return pollfd.revents;
+}
+
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)
+ if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
return 0;
+ /* If we have the privileges we will ignore the kernel limit. */
+
value = (int) n;
- r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value));
- if (r < 0)
- return -errno;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+ return -errno;
return 1;
}
bool in_initrd(void) {
- static __thread int saved = -1;
+ static int saved = -1;
struct statfs s;
if (saved >= 0)
@@ -1136,9 +1138,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int proc_cmdline(char **ret) {
int r;
- /* disable containers for now
if (detect_container(NULL) > 0) {
- char *buf, *p;
+ char *buf = NULL, *p;
size_t sz = 0;
r = read_full_file("/proc/1/cmdline", &buf, &sz);
@@ -1149,11 +1150,10 @@ int proc_cmdline(char **ret) {
if (*p == 0)
*p = ' ';
- *p = 0;
+ *p = 0;
*ret = buf;
return 1;
}
- */
r = read_one_line_file("/proc/cmdline", ret);
if (r < 0)
@@ -1185,3 +1185,54 @@ int getpeercred(int fd, struct ucred *ucred) {
*ucred = u;
return 0;
}
+
+/* This is much like like mkostemp() but is subject to umask(). */
+int mkostemp_safe(char *pattern, int flags) {
+ _cleanup_umask_ mode_t u;
+ int fd;
+
+ assert(pattern);
+
+ u = umask(077);
+
+ fd = mkostemp(pattern, flags);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+/* This is much like like mkstemp() but is subject to umask(). */
+int mkstemp_safe(char *pattern) {
+ _cleanup_umask_ mode_t u;
+ int fd;
+
+ assert(pattern);
+
+ u = umask(077);
+
+ fd = mkstemp(pattern);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+char *tempfn_xxxxxx(const char *p) {
+ const char *fn;
+ char *t;
+ size_t k;
+
+ assert(p);
+
+ t = new(char, strlen(p) + 1 + 6 + 1);
+ if (!t)
+ return NULL;
+
+ fn = basename(p);
+ k = fn - p;
+
+ strcpy(stpcpy(stpcpy(mempcpy(t, p, k), "."), fn), "XXXXXX");
+
+ return t;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 5fe724af40..4d05224542 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -32,6 +32,7 @@
#include <unistd.h>
#include <sys/socket.h>
+#include "time-util.h"
#include "missing.h"
#include "config.h"
@@ -127,7 +128,6 @@ 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);
@@ -158,6 +158,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pu
bool ignore_file(const char *filename) _pure_;
+int dev_urandom(void *p, size_t n);
void random_bytes(void *p, size_t n);
/* For basic lookup tables with strictly enumerated entries */
@@ -169,7 +170,8 @@ void random_bytes(void *p, size_t n);
} \
scope type name##_from_string(const char *s) { \
type i; \
- assert(s); \
+ if (!s) \
+ return (type) -1; \
for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
if (name##_table[i] && \
streq(name##_table[i], s)) \
@@ -267,6 +269,7 @@ const char *signal_to_string(int i) _const_;
extern int saved_argc;
extern char **saved_argv;
+int fd_wait_for_event(int fd, int event, usec_t timeout);
int fd_inc_sndbuf(int fd, size_t n);
bool in_initrd(void);
@@ -282,28 +285,24 @@ static inline void freep(void *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);
+ safe_close(*fd);
}
-static inline void closedirp(DIR **d) {
- if (*d)
- closedir(*d);
+static inline void umaskp(mode_t *u) {
+ umask(*u);
}
+DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
#define _cleanup_free_ _cleanup_(freep)
-#define _cleanup_fclose_ _cleanup_(fclosep)
#define _cleanup_close_ _cleanup_(closep)
+#define _cleanup_umask_ _cleanup_(umaskp)
+#define _cleanup_fclose_ _cleanup_(fclosep)
#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))
+ if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return malloc(a * b);
@@ -360,7 +359,12 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size,
int proc_cmdline(char **ret);
int getpeercred(int fd, struct ucred *ucred);
+int mkostemp_safe(char *pattern, int flags);
+int mkstemp_safe(char *pattern);
+
union file_handle_union {
struct file_handle handle;
char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
};
+
+char *tempfn_xxxxxx(const char *p);
diff --git a/src/shared/virt.c b/src/shared/virt.c
new file mode 100644
index 0000000000..2144341e83
--- /dev/null
+++ b/src/shared/virt.c
@@ -0,0 +1,328 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "virt.h"
+#include "fileio.h"
+
+#if 0
+static int detect_vm_cpuid(const char **_id) {
+
+ /* Both CPUID and DMI are x86 specific interfaces... */
+#if defined(__i386__) || defined(__x86_64__)
+
+ static const char cpuid_vendor_table[] =
+ "XenVMMXenVMM\0" "xen\0"
+ "KVMKVMKVM\0" "kvm\0"
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ "VMwareVMware\0" "vmware\0"
+ /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
+ "Microsoft Hv\0" "microsoft\0";
+
+ uint32_t eax, ecx;
+ union {
+ uint32_t sig32[3];
+ char text[13];
+ } sig = {};
+ const char *j, *k;
+ bool hypervisor;
+
+ /* http://lwn.net/Articles/301888/ */
+
+#if defined (__i386__)
+#define REG_a "eax"
+#define REG_b "ebx"
+#elif defined (__amd64__)
+#define REG_a "rax"
+#define REG_b "rbx"
+#endif
+
+ /* First detect whether there is a hypervisor */
+ eax = 1;
+ __asm__ __volatile__ (
+ /* ebx/rbx is being used for PIC! */
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=c" (ecx)
+ : "0" (eax)
+ );
+
+ hypervisor = !!(ecx & 0x80000000U);
+
+ if (hypervisor) {
+
+ /* There is a hypervisor, see what it is */
+ eax = 0x40000000U;
+ __asm__ __volatile__ (
+ /* ebx/rbx is being used for PIC! */
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " mov %%ebx, %1 \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+ : "0" (eax)
+ );
+
+ NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
+ if (streq(sig.text, j)) {
+ *_id = k;
+ return 1;
+ }
+
+ *_id = "other";
+ return 0;
+ }
+#endif
+
+ return 0;
+}
+
+static int detect_vm_dmi(const char **_id) {
+
+ /* Both CPUID and DMI are x86 specific interfaces... */
+#if defined(__i386__) || defined(__x86_64__)
+
+ static const char *const dmi_vendors[] = {
+ "/sys/class/dmi/id/sys_vendor",
+ "/sys/class/dmi/id/board_vendor",
+ "/sys/class/dmi/id/bios_vendor"
+ };
+
+ static const char dmi_vendor_table[] =
+ "QEMU\0" "qemu\0"
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ "VMware\0" "vmware\0"
+ "VMW\0" "vmware\0"
+ "innotek GmbH\0" "oracle\0"
+ "Xen\0" "xen\0"
+ "Bochs\0" "bochs\0";
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
+ _cleanup_free_ char *s = NULL;
+ const char *j, *k;
+ int r;
+
+ r = read_one_line_file(dmi_vendors[i], &s);
+ if (r < 0) {
+ if (r != -ENOENT)
+ return r;
+
+ continue;
+ }
+
+ NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
+ if (startswith(s, j)) {
+ *_id = k;
+ return 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+/* Returns a short identifier for the various VM implementations */
+int detect_vm(const char **id) {
+ _cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL;
+ static thread_local int cached_found = -1;
+ static thread_local const char *cached_id = NULL;
+ const char *_id = NULL;
+ int r;
+
+ if (_likely_(cached_found >= 0)) {
+
+ if (id)
+ *id = cached_id;
+
+ return cached_found;
+ }
+
+ /* Try xen capabilities file first, if not found try high-level hypervisor sysfs file:
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
+ r = read_one_line_file("/proc/xen/capabilities", &domcap);
+ if (r >= 0) {
+ char *cap, *i = domcap;
+
+ while ((cap = strsep(&i, ",")))
+ if (streq(cap, "control_d"))
+ break;
+
+ if (!cap) {
+ _id = "xen";
+ r = 1;
+ }
+
+ goto finish;
+
+ } else if (r == -ENOENT) {
+ _cleanup_free_ char *hvtype = NULL;
+
+ r = read_one_line_file("/sys/hypervisor/type", &hvtype);
+ if (r >= 0) {
+ if (streq(hvtype, "xen")) {
+ _id = "xen";
+ r = 1;
+ goto finish;
+ }
+ } else if (r != -ENOENT)
+ return r;
+ } else
+ return r;
+
+ /* this will set _id to "other" and return 0 for unknown hypervisors */
+ r = detect_vm_cpuid(&_id);
+ if (r != 0)
+ goto finish;
+
+ r = detect_vm_dmi(&_id);
+ if (r != 0)
+ goto finish;
+
+ if (_id) {
+ /* "other" */
+ r = 1;
+ goto finish;
+ }
+
+ /* Detect User-Mode Linux by reading /proc/cpuinfo */
+ r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
+ if (r < 0)
+ return r;
+ if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
+ _id = "uml";
+ r = 1;
+ goto finish;
+ }
+
+#if defined(__s390__)
+ {
+ _cleanup_free_ char *t = NULL;
+
+ r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
+ if (r >= 0) {
+ if (streq(t, "z/VM"))
+ _id = "zvm";
+ else
+ _id = "kvm";
+ r = 1;
+
+ goto finish;
+ }
+ }
+#endif
+
+ r = 0;
+
+finish:
+ cached_found = r;
+
+ cached_id = _id;
+ if (id)
+ *id = _id;
+
+ return r;
+}
+#endif
+
+int detect_container(const char **id) {
+
+ static thread_local int cached_found = -1;
+ static thread_local const char *cached_id = NULL;
+
+ _cleanup_free_ char *m = NULL;
+ const char *_id = NULL, *e = NULL;
+ int r;
+
+ if (_likely_(cached_found >= 0)) {
+
+ if (id)
+ *id = cached_id;
+
+ return cached_found;
+ }
+
+ /* /proc/vz exists in container and outside of the container,
+ * /proc/bc only outside of the container. */
+ if (access("/proc/vz", F_OK) >= 0 &&
+ access("/proc/bc", F_OK) < 0) {
+ _id = "openvz";
+ r = 1;
+ goto finish;
+ }
+
+ if (getpid() == 1) {
+ /* If we are PID 1 we can just check our own
+ * environment variable */
+
+ e = getenv("container");
+ if (isempty(e)) {
+ r = 0;
+ goto finish;
+ }
+ } else {
+
+ /* Otherwise, PID 1 dropped this information into a
+ * file in /run. This is better than accessing
+ * /proc/1/environ, since we don't need CAP_SYS_PTRACE
+ * for that. */
+
+ r = read_one_line_file("/run/systemd/container", &m);
+ if (r == -ENOENT) {
+ r = 0;
+ goto finish;
+ }
+ if (r < 0)
+ return r;
+
+ e = m;
+ }
+
+ /* We only recognize a selected few here, since we want to
+ * enforce a redacted namespace */
+ if (streq(e, "lxc"))
+ _id ="lxc";
+ else if (streq(e, "lxc-libvirt"))
+ _id = "lxc-libvirt";
+ else if (streq(e, "systemd-nspawn"))
+ _id = "systemd-nspawn";
+ else
+ _id = "other";
+
+ r = 1;
+
+finish:
+ cached_found = r;
+
+ cached_id = _id;
+ if (id)
+ *id = _id;
+
+ return r;
+}
diff --git a/src/shared/virt.h b/src/shared/virt.h
new file mode 100644
index 0000000000..571f3a71de
--- /dev/null
+++ b/src/shared/virt.h
@@ -0,0 +1,24 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 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 <http://www.gnu.org/licenses/>.
+***/
+
+int detect_container(const char **id);