diff options
-rw-r--r-- | src/shared/Makefile.am | 21 | ||||
-rw-r--r-- | src/shared/device-nodes.c | 6 | ||||
-rw-r--r-- | src/shared/fileio.c | 41 | ||||
-rw-r--r-- | src/shared/fileio.h | 1 | ||||
-rw-r--r-- | src/shared/label.c | 123 | ||||
-rw-r--r-- | src/shared/label.h | 2 | ||||
-rw-r--r-- | src/shared/log.c | 2 | ||||
-rw-r--r-- | src/shared/missing.h | 4 | ||||
-rw-r--r-- | src/shared/mkdir-label.c | 37 | ||||
-rw-r--r-- | src/shared/mkdir.c | 68 | ||||
-rw-r--r-- | src/shared/mkdir.h | 10 | ||||
-rw-r--r-- | src/shared/path-util.c | 33 | ||||
-rw-r--r-- | src/shared/path-util.h | 1 | ||||
-rw-r--r-- | src/shared/selinux-util.c | 49 | ||||
-rw-r--r-- | src/shared/selinux-util.h | 25 | ||||
-rw-r--r-- | src/shared/set.h | 4 | ||||
-rw-r--r-- | src/shared/smack-util.h | 6 | ||||
-rw-r--r-- | src/shared/strv.h | 6 | ||||
-rw-r--r-- | src/shared/utf8.c | 46 | ||||
-rw-r--r-- | src/shared/utf8.h | 7 | ||||
-rw-r--r-- | src/shared/util.c | 220 | ||||
-rw-r--r-- | src/shared/util.h | 6 | ||||
-rw-r--r-- | src/shared/virt.c | 224 |
23 files changed, 471 insertions, 471 deletions
diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am index 4c9f20697b..def06fd326 100644 --- a/src/shared/Makefile.am +++ b/src/shared/Makefile.am @@ -7,18 +7,20 @@ libudev_shared_la_SOURCES=\ cgroup-util.c \ conf-files.c \ device-nodes.c \ - dev-setup.c \ + dev-setup.c \ exit-status.c \ fileio.c \ hashmap.c \ - label.c \ + label.c \ log.c \ - mkdir.c \ + mkdir.c \ + mkdir-label.c \ MurmurHash2.c \ path-util.c \ + selinux-util.c \ set.c \ siphash24.c \ - smack-util.c \ + smack-util.c \ strbuf.c \ strv.c \ strxcpyx.c \ @@ -32,21 +34,22 @@ noinst_HEADERS = \ conf-files.h \ def.h \ device-nodes.h \ - dev-setup.h \ + dev-setup.h \ exit-status.h \ fileio.h \ hashmap.h \ ioprio.h \ - label.h \ + label.h \ log.h \ macro.h \ missing.h \ - mkdir.h \ + mkdir.h \ MurmurHash2.h \ path-util.h \ + selinux-util.h \ set.h \ siphash24.h \ - smack-util.h \ + smack-util.h \ socket-util.h \ sparse-endian.h \ strbuf.h \ @@ -55,7 +58,7 @@ noinst_HEADERS = \ time-util.h \ util.h \ utf8.h \ - udev-util.h \ + udev-util.h \ virt.h libudev_shared_la_LDFLAGS = \ diff --git a/src/shared/device-nodes.c b/src/shared/device-nodes.c index 5ddcaf042c..e235de83e1 100644 --- a/src/shared/device-nodes.c +++ b/src/shared/device-nodes.c @@ -21,8 +21,8 @@ #include <stdlib.h> #include <stdio.h> -#include <stdint.h> #include <string.h> +#include <stdint.h> #include <sys/types.h> #include "device-nodes.h" @@ -42,7 +42,7 @@ 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; + return -EINVAL; for (i = 0, j = 0; str[i] != '\0'; i++) { int seqlen; @@ -71,5 +71,5 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) { str_enc[j] = '\0'; return 0; err: - return -1; + return -EINVAL; } diff --git a/src/shared/fileio.c b/src/shared/fileio.c index fe27b23001..5ea4c1913b 100644 --- a/src/shared/fileio.c +++ b/src/shared/fileio.c @@ -83,29 +83,33 @@ int read_one_line_file(const char *fn, char **line) { return 0; } -int read_full_file(const char *fn, char **contents, size_t *size) { - _cleanup_fclose_ FILE *f = NULL; +int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; struct stat st; - assert(fn); + assert(f); 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 = LINE_MAX; - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; + if (S_ISREG(st.st_mode)) { + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + /* Start with the right file size, but be prepared for + * files from /proc which generally report a file size + * of 0 */ + if (st.st_size > 0) + n = st.st_size; + } + l = 0; for (;;) { char *t; size_t k; @@ -141,3 +145,16 @@ int read_full_file(const char *fn, char **contents, size_t *size) { return 0; } + +int read_full_file(const char *fn, char **contents, size_t *size) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(contents); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + return read_full_stream(f, contents, size); +} diff --git a/src/shared/fileio.h b/src/shared/fileio.h index 55c5d92486..d29e2dfa03 100644 --- a/src/shared/fileio.h +++ b/src/shared/fileio.h @@ -25,3 +25,4 @@ 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); +int read_full_stream(FILE *f, char **contents, size_t *size); diff --git a/src/shared/label.c b/src/shared/label.c index dca2a21228..eb95c31692 100644 --- a/src/shared/label.c +++ b/src/shared/label.c @@ -28,23 +28,54 @@ #include "label.h" #include "util.h" #include "path-util.h" +#include "selinux-util.h" +#include "smack-util.h" #ifdef HAVE_SELINUX -#include <stdbool.h> -#include <selinux/selinux.h> -#include <selinux/label.h> - static struct selabel_handle *label_hnd = NULL; -static int use_selinux_cached = -1; +#endif -bool use_selinux(void) { - if (use_selinux_cached < 0) - use_selinux_cached = is_selinux_enabled() > 0; +static int smack_relabel_in_dev(const char *path) { + int r = 0; - return use_selinux_cached; -} +#ifdef HAVE_SMACK + struct stat sb; + const char *label; + + /* + * Path must be in /dev and must exist + */ + if (!path_startswith(path, "/dev")) + return 0; + + r = lstat(path, &sb); + if (r < 0) + return -errno; + + /* + * Label directories and character devices "*". + * Label symlinks "_". + * Don't change anything else. + */ + if (S_ISDIR(sb.st_mode)) + label = SMACK_STAR_LABEL; + else if (S_ISLNK(sb.st_mode)) + label = SMACK_FLOOR_LABEL; + else if (S_ISCHR(sb.st_mode)) + label = SMACK_STAR_LABEL; + else + return 0; + + r = setxattr(path, "security.SMACK64", label, strlen(label), 0); + if (r < 0) { + log_error("Smack relabeling \"%s\" %m", path); + return -errno; + } #endif + return r; +} + int label_init(const char *prefix) { int r = 0; @@ -92,14 +123,14 @@ int label_init(const char *prefix) { return r; } -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +static int label_fix_selinux(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) + if (!label_hnd) return 0; r = lstat(path, &st); @@ -122,6 +153,7 @@ int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { if (r < 0) { /* Ignore ENOENT in some cases */ + if (ignore_enoent && errno == ENOENT) return 0; @@ -137,10 +169,31 @@ int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { return r; } +int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { + int r = 0; + + if (use_selinux()) { + r = label_fix_selinux(path, ignore_enoent, ignore_erofs); + if (r < 0) + return r; + } + + if (use_smack()) { + r = smack_relabel_in_dev(path); + if (r < 0) + return r; + } + + return r; +} + void label_finish(void) { #ifdef HAVE_SELINUX - if (use_selinux() && label_hnd) + if (!use_selinux()) + return; + + if (label_hnd) selabel_close(label_hnd); #endif } @@ -177,6 +230,8 @@ int label_context_set(const char *path, mode_t mode) { void label_context_clear(void) { #ifdef HAVE_SELINUX + PROTECT_ERRNO; + if (!use_selinux()) return; @@ -184,27 +239,26 @@ void label_context_clear(void) { #endif } -int label_mkdir(const char *path, mode_t mode, bool apply) { +static int label_mkdir_selinux(const char *path, mode_t mode) { + int r = 0; - /* Creates a directory and labels it according to the SELinux policy */ #ifdef HAVE_SELINUX - int r; + /* Creates a directory and labels it according to the SELinux policy */ security_context_t fcon = NULL; - if (!apply || !use_selinux() || !label_hnd) - goto skipped; + if (!label_hnd) + return 0; if (path_is_absolute(path)) r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR); else { - char *newpath; + _cleanup_free_ 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) @@ -226,12 +280,35 @@ int label_mkdir(const char *path, mode_t mode, bool apply) { finish: setfscreatecon(NULL); freecon(fcon); +#endif return r; +} -skipped: -#endif - return mkdir(path, mode) < 0 ? -errno : 0; +int label_mkdir(const char *path, mode_t mode) { + int r; + + if (use_selinux()) { + r = label_mkdir_selinux(path, mode); + if (r < 0) + return r; + } + + if (use_smack()) { + r = mkdir(path, mode); + if (r < 0 && errno != EEXIST) + return -errno; + + r = smack_relabel_in_dev(path); + if (r < 0) + return r; + } + + r = mkdir(path, mode); + if (r < 0 && errno != EEXIST) + return -errno; + + return 0; } int label_apply(const char *path, const char *label) { diff --git a/src/shared/label.h b/src/shared/label.h index a8dbcdc8b7..ec64fa6816 100644 --- a/src/shared/label.h +++ b/src/shared/label.h @@ -33,6 +33,6 @@ 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_mkdir(const char *path, mode_t mode); int label_apply(const char *path, const char *label); diff --git a/src/shared/log.c b/src/shared/log.c index 0237d20ff2..56aa4e14d4 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -30,11 +30,11 @@ #include <string.h> #include "log.h" -#include "time-util.h" #include "util.h" #include "missing.h" #include "macro.h" #include "socket-util.h" +#include "time-util.h" #define SNDBUF_SIZE (8*1024*1024) diff --git a/src/shared/missing.h b/src/shared/missing.h index 3c758956c6..2cb12786b7 100644 --- a/src/shared/missing.h +++ b/src/shared/missing.h @@ -78,10 +78,6 @@ static inline pid_t gettid(void) { } #endif -#ifndef MS_PRIVATE -#define MS_PRIVATE (1 << 18) -#endif - #ifndef MS_REC #define MS_REC 16384 #endif diff --git a/src/shared/mkdir-label.c b/src/shared/mkdir-label.c new file mode 100644 index 0000000000..073ecab7b9 --- /dev/null +++ b/src/shared/mkdir-label.c @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + 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 <http://www.gnu.org/licenses/>. +***/ + +#include <assert.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> + +#include "label.h" +#include "util.h" +#include "path-util.h" +#include "mkdir.h" + +int mkdir_parents_label(const char *path, mode_t mode) { + return mkdir_parents_internal(NULL, path, mode, label_mkdir); +} diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c index 770ee994c4..874433dc90 100644 --- a/src/shared/mkdir.c +++ b/src/shared/mkdir.c @@ -29,52 +29,24 @@ #include "label.h" #include "util.h" +#include "path-util.h" #include "mkdir.h" -static int is_dir(const char* path) { +int is_dir(const char* path, bool follow) { struct stat st; - if (stat(path, &st) < 0) - return -errno; + if (follow) { + if (stat(path, &st) < 0) + return -errno; + } else { + if (lstat(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) { +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { const char *p, *e; int r; @@ -97,7 +69,7 @@ static int mkdir_parents_internal(const char *prefix, const char *path, mode_t m memcpy(buf, path, e-path); buf[e-path] = 0; - r = is_dir(p); + r = is_dir(p, true); if (r > 0) return 0; if (r == 0) @@ -122,36 +94,32 @@ static int mkdir_parents_internal(const char *prefix, const char *path, mode_t m if (prefix && path_startswith(prefix, t)) continue; - r = label_mkdir(t, mode, apply); + r = _mkdir(t, mode); 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); + return mkdir_parents_internal(NULL, path, mode, mkdir); } -static int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, bool apply) { +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { int r; /* Like mkdir -p */ - r = mkdir_parents_internal(prefix, path, mode, apply); + r = mkdir_parents_internal(prefix, path, mode, _mkdir); if (r < 0) return r; - r = label_mkdir(path, mode, apply); - if (r < 0 && (errno != EEXIST || is_dir(path) <= 0)) + r = _mkdir(path, mode); + if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0)) return -errno; return 0; } int mkdir_p(const char *path, mode_t mode) { - return mkdir_p_internal(NULL, path, mode, false); + return mkdir_p_internal(NULL, path, mode, mkdir); } diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h index 24ffa6364c..399f2c0ff6 100644 --- a/src/shared/mkdir.h +++ b/src/shared/mkdir.h @@ -1,7 +1,6 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ -#ifndef foomkdirhfoo -#define foomkdirhfoo +#pragma once /*** This file is part of systemd. @@ -22,8 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -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 + +/* internally used */ +typedef int (*mkdir_func_t)(const char *pathname, mode_t mode); +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); diff --git a/src/shared/path-util.c b/src/shared/path-util.c index 783d130842..2a2f33dbca 100644 --- a/src/shared/path-util.c +++ b/src/shared/path-util.c @@ -248,6 +248,39 @@ char *path_kill_slashes(char *path) { return path; } +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; + } +} + bool path_equal(const char *a, const char *b) { assert(a); assert(b); diff --git a/src/shared/path-util.h b/src/shared/path-util.h index a62624c1b3..e0cab15a3e 100644 --- a/src/shared/path-util.h +++ b/src/shared/path-util.h @@ -27,6 +27,7 @@ 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); +char* path_startswith(const char *path, const char *prefix) _pure_; bool path_equal(const char *a, const char *b) _pure_; char** path_strv_resolve(char **l, const char *prefix); diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c new file mode 100644 index 0000000000..16c74a4ac0 --- /dev/null +++ b/src/shared/selinux-util.c @@ -0,0 +1,49 @@ +/*** + 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 <http://www.gnu.org/licenses/>. +***/ + +#include "selinux-util.h" + +#ifdef HAVE_SELINUX + +#include <selinux/selinux.h> + +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; +} + +void retest_selinux(void) { + use_selinux_cached = -1; +} + +#else + +bool use_selinux(void) { + return false; +} + +void retest_selinux(void) { +} + +#endif diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h new file mode 100644 index 0000000000..b5b8faa06a --- /dev/null +++ b/src/shared/selinux-util.h @@ -0,0 +1,25 @@ +/*** + 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 <http://www.gnu.org/licenses/>. +***/ + +#pragma once + +#include <stdbool.h> + +bool use_selinux(void); +void retest_selinux(void); diff --git a/src/shared/set.h b/src/shared/set.h index c6455be7c1..dd4d458792 100644 --- a/src/shared/set.h +++ b/src/shared/set.h @@ -34,9 +34,6 @@ 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); @@ -45,4 +42,5 @@ bool set_contains(Set *s, void *value); void *set_iterate(Set *s, Iterator *i); void *set_iterate_backwards(Set *s, Iterator *i); +DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); #define _cleanup_set_free_ _cleanup_(set_freep) diff --git a/src/shared/smack-util.h b/src/shared/smack-util.h index 88704894e7..5e555def2b 100644 --- a/src/shared/smack-util.h +++ b/src/shared/smack-util.h @@ -19,9 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#pragma once + #include <stdbool.h> +#define SMACK_FLOOR_LABEL "_" +#define SMACK_STAR_LABEL "*" + 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); diff --git a/src/shared/strv.h b/src/shared/strv.h index 4cc918367e..98e339c02f 100644 --- a/src/shared/strv.h +++ b/src/shared/strv.h @@ -27,11 +27,7 @@ #include "macro.h" void strv_free(char **l); -static inline void strv_freep(char ***l) { - strv_free(*l); -} - -void strv_free(char **l); +DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); #define _cleanup_strv_free_ _cleanup_(strv_freep) char **strv_copy(char * const *l); diff --git a/src/shared/utf8.c b/src/shared/utf8.c index 1044fb6489..403166d7f9 100644 --- a/src/shared/utf8.c +++ b/src/shared/utf8.c @@ -78,8 +78,11 @@ static bool is_unicode_control(uint32_t ch) { /* 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]; + unsigned char c; + assert(str); + + c = (unsigned char) str[0]; if (c < 0x80) return 1; if ((c & 0xe0) == 0xc0) @@ -92,16 +95,18 @@ static int utf8_encoded_expected_len(const char *str) { 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; + int unichar, len, i; + + assert(str); len = utf8_encoded_expected_len(str); + switch (len) { case 1: return (int)str[0]; @@ -121,12 +126,12 @@ int utf8_encoded_to_unichar(const char *str) { unichar = (int)str[0] & 0x01; break; default: - return -1; + return -EINVAL; } for (i = 1; i < len; i++) { if (((int)str[i] & 0xc0) != 0x80) - return -1; + return -EINVAL; unichar <<= 6; unichar |= (int)str[i] & 0x3f; } @@ -134,16 +139,21 @@ int utf8_encoded_to_unichar(const char *str) { return unichar; } -bool utf8_is_printable(const char* str, size_t length) { +bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { 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); + int encoded_len, val; - if (encoded_len < 0 || val < 0 || is_unicode_control(val)) + encoded_len = utf8_encoded_valid_unichar((const char *) p); + val = utf8_encoded_to_unichar((const char*) p); + + if (encoded_len < 0 || + val < 0 || + is_unicode_control(val) || + (!newline && val == '\n')) return false; length -= encoded_len; @@ -203,6 +213,7 @@ char *utf16_to_utf8(const void *s, size_t length) { /* 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) @@ -213,18 +224,19 @@ static int utf8_unichar_to_encoded_len(int unichar) { 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; + int len, unichar, i; + + assert(str); len = utf8_encoded_expected_len(str); if (len == 0) - return -1; + return -EINVAL; /* ascii is valid */ if (len == 1) @@ -233,17 +245,17 @@ int utf8_encoded_valid_unichar(const char *str) { /* check if expected encoded chars are available */ for (i = 0; i < len; i++) if ((str[i] & 0x80) != 0x80) - return -1; + return -EINVAL; unichar = utf8_encoded_to_unichar(str); /* check if encoded length matches encoded value */ if (utf8_unichar_to_encoded_len(unichar) != len) - return -1; + return -EINVAL; /* check if value has valid range */ if (!is_unicode_valid(unichar)) - return -1; + return -EINVAL; return len; } diff --git a/src/shared/utf8.h b/src/shared/utf8.h index 9d09153c1c..24232247f5 100644 --- a/src/shared/utf8.h +++ b/src/shared/utf8.h @@ -17,13 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#pragma once + #include <stdbool.h> #include "macro.h" char *ascii_is_valid(const char *s) _pure_; -bool utf8_is_printable(const char* str, size_t length) _pure_; +bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; +_pure_ static inline bool utf8_is_printable(const char* str, size_t length) { + return utf8_is_printable_newline(str, length, true); +} char *utf16_to_utf8(const void *s, size_t length); diff --git a/src/shared/util.c b/src/shared/util.c index d551f87e60..41fe240433 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -543,6 +543,77 @@ int open_terminal(const char *name, int mode) { return fd; } +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; + } +} + +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 dev_urandom(void *p, size_t n) { _cleanup_close_ int fd; ssize_t k; @@ -606,41 +677,6 @@ _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); @@ -720,81 +756,6 @@ bool nulstr_contains(const char*nulstr, const char *needle) { 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; @@ -1236,3 +1197,42 @@ char *tempfn_xxxxxx(const char *p) { return t; } + +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; + + } +} diff --git a/src/shared/util.h b/src/shared/util.h index 4d05224542..dd1c515f90 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -148,8 +148,8 @@ 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 octchar(int x) _const_; char *cescape(const char *s); char *xescape(const char *s, const char *bad); @@ -229,8 +229,6 @@ 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_; @@ -368,3 +366,5 @@ union file_handle_union { }; char *tempfn_xxxxxx(const char *p); + +int execute_command(const char *command, char *const argv[]); diff --git a/src/shared/virt.c b/src/shared/virt.c index 2144341e83..92ca4ec883 100644 --- a/src/shared/virt.c +++ b/src/shared/virt.c @@ -27,230 +27,6 @@ #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; |