chiark / gitweb /
condition: unify condition logic in one file
authorLennart Poettering <lennart@poettering.net>
Thu, 6 Nov 2014 00:40:37 +0000 (01:40 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 6 Nov 2014 13:21:10 +0000 (14:21 +0100)
Makefile.am
src/core/condition.c
src/shared/condition-util.c
src/shared/condition-util.h
src/shared/util.c
src/test/test-condition-util.c

index f614b86c07b56b9dc66f734836a933bea5032b56..452f07ca75a86b4d5ecdc9ceeb4ed6de210500a7 100644 (file)
@@ -1524,8 +1524,9 @@ test_condition_util_SOURCES = \
 
 test_condition_util_LDADD = \
        libsystemd-shared.la \
-       libsystemd-internal.la
-
+       libsystemd-internal.la \
+       libsystemd-capability.la \
+       libsystemd-label.la
 
 test_fdset_SOURCES = \
        src/test/test-fdset.c
index 32135ec5b2b83242a5a9c918c40b8356b2ca0128..d8d11528eca33a90c59c9527c76cdf1a41960714 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/capability.h>
-#include <sys/statvfs.h>
-#include <fnmatch.h>
-
-#include "sd-id128.h"
-#include "util.h"
 #include "condition.h"
-#include "virt.h"
-#include "path-util.h"
-#include "fileio.h"
 #include "unit.h"
-#include "smack-util.h"
-#include "apparmor-util.h"
-#include "ima-util.h"
-#include "selinux-util.h"
-#include "audit.h"
-
-static int condition_test_security(Condition *c) {
-        assert(c);
-        assert(c->parameter);
-        assert(c->type == CONDITION_SECURITY);
-
-        if (streq(c->parameter, "selinux"))
-                return mac_selinux_use() == !c->negate;
-        if (streq(c->parameter, "smack"))
-                return mac_smack_use() == !c->negate;
-        if (streq(c->parameter, "apparmor"))
-                return mac_apparmor_use() == !c->negate;
-        if (streq(c->parameter, "audit"))
-                return use_audit() == !c->negate;
-        if (streq(c->parameter, "ima"))
-                return use_ima() == !c->negate;
-
-        return c->negate;
-}
-
-static int condition_test_capability(Condition *c) {
-        _cleanup_fclose_ FILE *f = NULL;
-        cap_value_t value;
-        char line[LINE_MAX];
-        unsigned long long capabilities = -1;
-
-        assert(c);
-        assert(c->parameter);
-        assert(c->type == CONDITION_CAPABILITY);
-
-        /* If it's an invalid capability, we don't have it */
-
-        if (cap_from_name(c->parameter, &value) < 0)
-                return -EINVAL;
-
-        /* If it's a valid capability we default to assume
-         * that we have it */
-
-        f = fopen("/proc/self/status", "re");
-        if (!f)
-                return -errno;
-
-        while (fgets(line, sizeof(line), f)) {
-                truncate_nl(line);
-
-                if (startswith(line, "CapBnd:")) {
-                        (void) sscanf(line+7, "%llx", &capabilities);
-                        break;
-                }
-        }
-
-        return !!(capabilities & (1ULL << value)) == !c->negate;
-}
-
-static bool condition_test_needs_update(Condition *c) {
-        const char *p;
-        struct stat usr, other;
-
-        assert(c);
-        assert(c->parameter);
-        assert(c->type == CONDITION_NEEDS_UPDATE);
-
-        /* If the file system is read-only we shouldn't suggest an update */
-        if (path_is_read_only_fs(c->parameter) > 0)
-                return c->negate;
-
-        /* Any other failure means we should allow the condition to be true,
-         * so that we rather invoke too many update tools then too
-         * few. */
-
-        if (!path_is_absolute(c->parameter))
-                return !c->negate;
-
-        p = strappenda(c->parameter, "/.updated");
-        if (lstat(p, &other) < 0)
-                return !c->negate;
-
-        if (lstat("/usr/", &usr) < 0)
-                return !c->negate;
-
-        return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
-                (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
-}
-
-static bool condition_test_first_boot(Condition *c) {
-        int r;
-
-        assert(c);
-        assert(c->parameter);
-        assert(c->type == CONDITION_FIRST_BOOT);
-
-        r = parse_boolean(c->parameter);
-        if (r < 0)
-                return r;
-
-        return ((access("/run/systemd/first-boot", F_OK) >= 0) == !!r) == !c->negate;
-}
-
-static int condition_test(Condition *c) {
-        assert(c);
-
-        switch(c->type) {
-
-        case CONDITION_PATH_EXISTS:
-                return (access(c->parameter, F_OK) >= 0) == !c->negate;
-
-        case CONDITION_PATH_EXISTS_GLOB:
-                return (glob_exists(c->parameter) > 0) == !c->negate;
-
-        case CONDITION_PATH_IS_DIRECTORY: {
-                struct stat st;
-
-                if (stat(c->parameter, &st) < 0)
-                        return c->negate;
-                return S_ISDIR(st.st_mode) == !c->negate;
-        }
-
-        case CONDITION_PATH_IS_SYMBOLIC_LINK: {
-                struct stat st;
-
-                if (lstat(c->parameter, &st) < 0)
-                        return c->negate;
-                return S_ISLNK(st.st_mode) == !c->negate;
-        }
-
-        case CONDITION_PATH_IS_MOUNT_POINT:
-                return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
-
-        case CONDITION_PATH_IS_READ_WRITE:
-                return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
-
-        case CONDITION_DIRECTORY_NOT_EMPTY: {
-                int k;
-
-                k = dir_is_empty(c->parameter);
-                return !(k == -ENOENT || k > 0) == !c->negate;
-        }
-
-        case CONDITION_FILE_NOT_EMPTY: {
-                struct stat st;
-
-                if (stat(c->parameter, &st) < 0)
-                        return c->negate;
-
-                return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
-        }
-
-        case CONDITION_FILE_IS_EXECUTABLE: {
-                struct stat st;
-
-                if (stat(c->parameter, &st) < 0)
-                        return c->negate;
-
-                return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
-        }
-
-        case CONDITION_KERNEL_COMMAND_LINE:
-                return condition_test_kernel_command_line(c);
-
-        case CONDITION_VIRTUALIZATION:
-                return condition_test_virtualization(c);
-
-        case CONDITION_SECURITY:
-                return condition_test_security(c);
-
-        case CONDITION_CAPABILITY:
-                return condition_test_capability(c);
-
-        case CONDITION_HOST:
-                return condition_test_host(c);
-
-        case CONDITION_AC_POWER:
-                return condition_test_ac_power(c);
-
-        case CONDITION_ARCHITECTURE:
-                return condition_test_architecture(c);
-
-        case CONDITION_NEEDS_UPDATE:
-                return condition_test_needs_update(c);
-
-        case CONDITION_FIRST_BOOT:
-                return condition_test_first_boot(c);
-
-        case CONDITION_NULL:
-                return !c->negate;
-
-        default:
-                assert_not_reached("Invalid condition type.");
-        }
-}
 
 bool condition_test_list(const char *unit, Condition *first) {
         Condition *c;
index 33752c8f9104ed5a904e83a73e8a1336ccbe2c95..ab889e32225376d3e0acd45020b856adaf06e831 100644 (file)
@@ -26,7 +26,7 @@
 #include <sys/statvfs.h>
 #include <fnmatch.h>
 
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
 #include "util.h"
 #include "condition-util.h"
 #include "virt.h"
 #include "fileio.h"
 #include "unit.h"
 #include "architecture.h"
+#include "virt.h"
+#include "smack-util.h"
+#include "apparmor-util.h"
+#include "ima-util.h"
+#include "selinux-util.h"
+#include "audit.h"
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
         Condition *c;
+        int r;
 
         assert(type < _CONDITION_TYPE_MAX);
 
@@ -48,12 +55,10 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
         c->trigger = trigger;
         c->negate = negate;
 
-        if (parameter) {
-                c->parameter = strdup(parameter);
-                if (!c->parameter) {
-                        free(c);
-                        return NULL;
-                }
+        r = free_and_strdup(&c->parameter, parameter);
+        if (r < 0) {
+                free(c);
+                return NULL;
         }
 
         return c;
@@ -210,6 +215,227 @@ int condition_test_ac_power(Condition *c) {
         return ((on_ac_power() != 0) == !!r) == !c->negate;
 }
 
+static int condition_test_security(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_SECURITY);
+
+        if (streq(c->parameter, "selinux"))
+                return mac_selinux_use() == !c->negate;
+        if (streq(c->parameter, "smack"))
+                return mac_smack_use() == !c->negate;
+        if (streq(c->parameter, "apparmor"))
+                return mac_apparmor_use() == !c->negate;
+        if (streq(c->parameter, "audit"))
+                return use_audit() == !c->negate;
+        if (streq(c->parameter, "ima"))
+                return use_ima() == !c->negate;
+
+        return c->negate;
+}
+
+static int condition_test_capability(Condition *c) {
+        _cleanup_fclose_ FILE *f = NULL;
+        cap_value_t value;
+        char line[LINE_MAX];
+        unsigned long long capabilities = -1;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_CAPABILITY);
+
+        /* If it's an invalid capability, we don't have it */
+
+        if (cap_from_name(c->parameter, &value) < 0)
+                return -EINVAL;
+
+        /* If it's a valid capability we default to assume
+         * that we have it */
+
+        f = fopen("/proc/self/status", "re");
+        if (!f)
+                return -errno;
+
+        while (fgets(line, sizeof(line), f)) {
+                truncate_nl(line);
+
+                if (startswith(line, "CapBnd:")) {
+                        (void) sscanf(line+7, "%llx", &capabilities);
+                        break;
+                }
+        }
+
+        return !!(capabilities & (1ULL << value)) == !c->negate;
+}
+
+static int condition_test_needs_update(Condition *c) {
+        const char *p;
+        struct stat usr, other;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_NEEDS_UPDATE);
+
+        /* If the file system is read-only we shouldn't suggest an update */
+        if (path_is_read_only_fs(c->parameter) > 0)
+                return c->negate;
+
+        /* Any other failure means we should allow the condition to be true,
+         * so that we rather invoke too many update tools then too
+         * few. */
+
+        if (!path_is_absolute(c->parameter))
+                return !c->negate;
+
+        p = strappenda(c->parameter, "/.updated");
+        if (lstat(p, &other) < 0)
+                return !c->negate;
+
+        if (lstat("/usr/", &usr) < 0)
+                return !c->negate;
+
+        return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
+                (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
+}
+
+static int condition_test_first_boot(Condition *c) {
+        int r;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_FIRST_BOOT);
+
+        r = parse_boolean(c->parameter);
+        if (r < 0)
+                return r;
+
+        return ((access("/run/systemd/first-boot", F_OK) >= 0) == !!r) == !c->negate;
+}
+
+static int condition_test_path_exists(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_EXISTS);
+
+        return (access(c->parameter, F_OK) >= 0) == !c->negate;
+}
+
+static int condition_test_path_exists_glob(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_EXISTS_GLOB);
+
+        return (glob_exists(c->parameter) > 0) == !c->negate;
+}
+
+static int condition_test_path_is_directory(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_IS_DIRECTORY);
+
+        return (is_dir(c->parameter, true) > 0) == !c->negate;
+}
+
+static int condition_test_path_is_symbolic_link(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
+
+        return (is_symlink(c->parameter) > 0) == !c->negate;
+}
+
+static int condition_test_path_is_mount_point(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
+
+        return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
+}
+
+static int condition_test_path_is_read_write(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_IS_READ_WRITE);
+
+        return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
+}
+
+static int condition_test_directory_not_empty(Condition *c) {
+        int r;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_DIRECTORY_NOT_EMPTY);
+
+        r = dir_is_empty(c->parameter);
+        return !(r == -ENOENT || r > 0) == !c->negate;
+}
+
+static int condition_test_file_not_empty(Condition *c) {
+        struct stat st;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_FILE_NOT_EMPTY);
+
+        return (stat(c->parameter, &st) >= 0 &&
+                S_ISREG(st.st_mode) &&
+                st.st_size > 0) == !c->negate;
+}
+
+static int condition_test_file_is_executable(Condition *c) {
+        struct stat st;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_FILE_IS_EXECUTABLE);
+
+        return (stat(c->parameter, &st) >= 0 &&
+                S_ISREG(st.st_mode) &&
+                (st.st_mode & 0111)) == !c->negate;
+}
+
+static int condition_test_null(Condition *c) {
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_NULL);
+
+        /* Note that during parsing we already evaluate the string and
+         * store it in c->negate */
+        return !c->negate;
+}
+
+int condition_test(Condition *c) {
+
+        static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
+                [CONDITION_PATH_EXISTS] = condition_test_path_exists,
+                [CONDITION_PATH_EXISTS_GLOB] = condition_test_path_exists_glob,
+                [CONDITION_PATH_IS_DIRECTORY] = condition_test_path_is_directory,
+                [CONDITION_PATH_IS_SYMBOLIC_LINK] = condition_test_path_is_symbolic_link,
+                [CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
+                [CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
+                [CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
+                [CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
+                [CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
+                [CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
+                [CONDITION_VIRTUALIZATION] = condition_test_virtualization,
+                [CONDITION_SECURITY] = condition_test_security,
+                [CONDITION_CAPABILITY] = condition_test_capability,
+                [CONDITION_HOST] = condition_test_host,
+                [CONDITION_AC_POWER] = condition_test_ac_power,
+                [CONDITION_ARCHITECTURE] = condition_test_architecture,
+                [CONDITION_NEEDS_UPDATE] = condition_test_needs_update,
+                [CONDITION_FIRST_BOOT] = condition_test_first_boot,
+                [CONDITION_NULL] = condition_test_null,
+        };
+
+        assert(c);
+        assert(c->type >= 0);
+        assert(c->type < _CONDITION_TYPE_MAX);
+
+        return condition_tests[c->type](c);
+}
+
 void condition_dump(Condition *c, FILE *f, const char *prefix) {
         assert(c);
         assert(f);
index fbb815008312cb89dbfcc9ef34b6531e7d9b14ef..deeb6b4257b3bde1e168ccbe46db9d6c4361e6a1 100644 (file)
@@ -83,6 +83,8 @@ int condition_test_architecture(Condition *c);
 int condition_test_host(Condition *c);
 int condition_test_ac_power(Condition *c);
 
+int condition_test(Condition *c);
+
 void condition_dump(Condition *c, FILE *f, const char *prefix);
 void condition_dump_list(Condition *c, FILE *f, const char *prefix);
 
index d33f349d816d9a667b236e420609c6e519d2de37..39ce46adb4dd19c10d5522f0c61e6271c5ff0426 100644 (file)
@@ -6987,14 +6987,14 @@ int is_symlink(const char *path) {
 
 int is_dir(const char* path, bool follow) {
         struct stat st;
+        int r;
 
-        if (follow) {
-                if (stat(path, &st) < 0)
-                        return -errno;
-        } else {
-                if (lstat(path, &st) < 0)
-                        return -errno;
-        }
+        if (follow)
+                r = stat(path, &st);
+        else
+                r = lstat(path, &st);
+        if (r < 0)
+                return -errno;
 
         return !!S_ISDIR(st.st_mode);
 }
index 7a247fbdbdcc47a8d0f8131acb8bd754f6026f9b..4f9ae8ab907fd5b36d7475bd5632346aa80ab966 100644 (file)
 #include "util.h"
 #include "log.h"
 #include "architecture.h"
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
+
+static void test_condition_test_path_exists(void) {
+        Condition *condition;
+
+        condition = condition_new(CONDITION_PATH_EXISTS, "/bin/sh", false, false);
+        assert_se(condition_test(condition));
+        condition_free(condition);
+
+        condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, false);
+        assert_se(!condition_test(condition));
+        condition_free(condition);
+
+        condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, true);
+        assert_se(condition_test(condition));
+        condition_free(condition);
+}
 
 static void test_condition_test_ac_power(void) {
         Condition *condition;
 
         condition = condition_new(CONDITION_AC_POWER, "true", false, false);
-        assert_se(condition_test_ac_power(condition) == on_ac_power());
+        assert_se(condition_test(condition) == on_ac_power());
         condition_free(condition);
 
         condition = condition_new(CONDITION_AC_POWER, "false", false, false);
-        assert_se(condition_test_ac_power(condition) != on_ac_power());
+        assert_se(condition_test(condition) != on_ac_power());
         condition_free(condition);
 
         condition = condition_new(CONDITION_AC_POWER, "false", false, true);
-        assert_se(condition_test_ac_power(condition) == on_ac_power());
+        assert_se(condition_test(condition) == on_ac_power());
         condition_free(condition);
 }
 
@@ -52,22 +68,22 @@ static void test_condition_test_host(void) {
         assert_se(sd_id128_to_string(id, sid));
 
         condition = condition_new(CONDITION_HOST, sid, false, false);
-        assert_se(condition_test_host(condition));
+        assert_se(condition_test(condition));
         condition_free(condition);
 
         condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false);
-        assert_se(!condition_test_host(condition));
+        assert_se(!condition_test(condition));
         condition_free(condition);
 
         condition = condition_new(CONDITION_HOST, sid, false, true);
-        assert_se(!condition_test_host(condition));
+        assert_se(!condition_test(condition));
         condition_free(condition);
 
         hostname = gethostname_malloc();
         assert_se(hostname);
 
         condition = condition_new(CONDITION_HOST, hostname, false, false);
-        assert_se(condition_test_host(condition));
+        assert_se(condition_test(condition));
         condition_free(condition);
 }
 
@@ -83,15 +99,15 @@ static void test_condition_test_architecture(void) {
         assert_se(sa);
 
         condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false);
-        assert_se(condition_test_architecture(condition));
+        assert_se(condition_test(condition));
         condition_free(condition);
 
         condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false);
-        assert_se(condition_test_architecture(condition) < 0);
+        assert_se(condition_test(condition) < 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true);
-        assert_se(!condition_test_architecture(condition));
+        assert_se(!condition_test(condition));
         condition_free(condition);
 }
 
@@ -99,11 +115,11 @@ static void test_condition_test_kernel_command_line(void) {
         Condition *condition;
 
         condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "thisreallyshouldntbeonthekernelcommandline", false, false);
-        assert_se(!condition_test_kernel_command_line(condition));
+        assert_se(!condition_test(condition));
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "andthis=neither", false, false);
-        assert_se(!condition_test_kernel_command_line(condition));
+        assert_se(!condition_test(condition));
         condition_free(condition);
 }
 
@@ -111,6 +127,7 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
+        test_condition_test_path_exists();
         test_condition_test_ac_power();
         test_condition_test_host();
         test_condition_test_architecture();