return head;
}
-static int condition_test_kernel_command_line(Condition *c) {
+static int condition_test_kernel_command_line(Condition *c, char **env) {
_cleanup_free_ char *line = NULL;
const char *p;
bool equal;
}
}
-static int condition_test_kernel_version(Condition *c) {
+static int condition_test_kernel_version(Condition *c, char **env) {
OrderOperator order;
struct utsname u;
const char *p;
return true;
}
-static int condition_test_memory(Condition *c) {
+static int condition_test_memory(Condition *c, char **env) {
OrderOperator order;
uint64_t m, k;
const char *p;
return test_order(CMP(m, k), order);
}
-static int condition_test_cpus(Condition *c) {
+static int condition_test_cpus(Condition *c, char **env) {
OrderOperator order;
const char *p;
unsigned k;
return test_order(CMP((unsigned) n, k), order);
}
-static int condition_test_user(Condition *c) {
+static int condition_test_user(Condition *c, char **env) {
uid_t id;
int r;
_cleanup_free_ char *username = NULL;
return id == getuid() || id == geteuid();
}
-static int condition_test_control_group_controller(Condition *c) {
+static int condition_test_control_group_controller(Condition *c, char **env) {
int r;
CGroupMask system_mask, wanted_mask = 0;
return FLAGS_SET(system_mask, wanted_mask);
}
-static int condition_test_group(Condition *c) {
+static int condition_test_group(Condition *c, char **env) {
gid_t id;
int r;
return in_group(c->parameter) > 0;
}
-static int condition_test_virtualization(Condition *c) {
+static int condition_test_virtualization(Condition *c, char **env) {
int b, v;
assert(c);
return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
}
-static int condition_test_architecture(Condition *c) {
+static int condition_test_architecture(Condition *c, char **env) {
int a, b;
assert(c);
return a == b;
}
-static int condition_test_host(Condition *c) {
+static int condition_test_host(Condition *c, char **env) {
_cleanup_free_ char *h = NULL;
sd_id128_t x, y;
int r;
return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
}
-static int condition_test_ac_power(Condition *c) {
+static int condition_test_ac_power(Condition *c, char **env) {
int r;
assert(c);
return (on_ac_power() != 0) == !!r;
}
-static int condition_test_security(Condition *c) {
+static int condition_test_security(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_SECURITY);
return false;
}
-static int condition_test_capability(Condition *c) {
+static int condition_test_capability(Condition *c, char **env) {
unsigned long long capabilities = (unsigned long long) -1;
_cleanup_fclose_ FILE *f = NULL;
int value, r;
return !!(capabilities & (1ULL << value));
}
-static int condition_test_needs_update(Condition *c) {
- const char *p;
+static int condition_test_needs_update(Condition *c, char **env) {
struct stat usr, other;
+ const char *p;
+ bool b;
+ int r;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_NEEDS_UPDATE);
+ r = proc_cmdline_get_bool("systemd.condition-needs-update", &b);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-needs-update= kernel command line argument, ignoring: %m");
+ if (r > 0)
+ return b;
+
+ if (!path_is_absolute(c->parameter)) {
+ log_debug("Specified condition parameter '%s' is not absolute, assuming an update is needed.", c->parameter);
+ return true;
+ }
+
/* If the file system is read-only we shouldn't suggest an update */
- if (path_is_read_only_fs(c->parameter) > 0)
+ r = path_is_read_only_fs(c->parameter);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine if '%s' is read-only, ignoring: %m", c->parameter);
+ if (r > 0)
return false;
- /* Any other failure means we should allow the condition to be true,
- * so that we rather invoke too many update tools than too
- * few. */
-
- if (!path_is_absolute(c->parameter))
- return true;
+ /* Any other failure means we should allow the condition to be true, so that we rather invoke too
+ * many update tools than too few. */
p = strjoina(c->parameter, "/.updated");
- if (lstat(p, &other) < 0)
+ if (lstat(p, &other) < 0) {
+ if (errno != ENOENT)
+ log_debug_errno(errno, "Failed to stat() '%s', assuming an update is needed: %m", p);
return true;
+ }
- if (lstat("/usr/", &usr) < 0)
+ if (lstat("/usr/", &usr) < 0) {
+ log_debug_errno(errno, "Failed to stat() /usr/, assuming an update is needed: %m");
return true;
+ }
/*
* First, compare seconds as they are always accurate...
* AND the target file's nanoseconds == 0
* (otherwise the filesystem supports nsec timestamps, see stat(2)).
*/
- if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
- _cleanup_free_ char *timestamp_str = NULL;
- uint64_t timestamp;
- int r;
+ if (usr.st_mtim.tv_nsec == 0 || other.st_mtim.tv_nsec > 0)
+ return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
- r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
- if (r < 0) {
- log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
- return true;
- } else if (r == 0) {
- log_debug("No data in timestamp file '%s', using mtime", p);
- return true;
- }
-
- r = safe_atou64(timestamp_str, ×tamp);
- if (r < 0) {
- log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
- return true;
- }
+ _cleanup_free_ char *timestamp_str = NULL;
+ r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
+ return true;
+ } else if (r == 0) {
+ log_debug("No data in timestamp file '%s', using mtime.", p);
+ return true;
+ }
- timespec_store(&other.st_mtim, timestamp);
+ uint64_t timestamp;
+ r = safe_atou64(timestamp_str, ×tamp);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
+ return true;
}
- return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
+ return timespec_load_nsec(&usr.st_mtim) > timestamp;
}
-static int condition_test_first_boot(Condition *c) {
- int r;
+static int condition_test_first_boot(Condition *c, char **env) {
+ int r, q;
+ bool b;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_FIRST_BOOT);
+ r = proc_cmdline_get_bool("systemd.condition-first-boot", &b);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel command line argument, ignoring: %m");
+ if (r > 0)
+ return b == !!r;
+
r = parse_boolean(c->parameter);
if (r < 0)
return r;
- return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
+ q = access("/run/systemd/first-boot", F_OK);
+ if (q < 0 && errno != ENOENT)
+ log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, ignoring: %m");
+
+ return (q >= 0) == !!r;
+}
+
+static int condition_test_environment(Condition *c, char **env) {
+ bool equal;
+ char **i;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_ENVIRONMENT);
+
+ equal = strchr(c->parameter, '=');
+
+ STRV_FOREACH(i, env) {
+ bool found;
+
+ if (equal)
+ found = streq(c->parameter, *i);
+ else {
+ const char *f;
+
+ f = startswith(*i, c->parameter);
+ found = f && IN_SET(*f, 0, '=');
+ }
+
+ if (found)
+ return true;
+ }
+
+ return false;
}
-static int condition_test_path_exists(Condition *c) {
+static int condition_test_path_exists(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_EXISTS);
return access(c->parameter, F_OK) >= 0;
}
-static int condition_test_path_exists_glob(Condition *c) {
+static int condition_test_path_exists_glob(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_EXISTS_GLOB);
return glob_exists(c->parameter) > 0;
}
-static int condition_test_path_is_directory(Condition *c) {
+static int condition_test_path_is_directory(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_DIRECTORY);
return is_dir(c->parameter, true) > 0;
}
-static int condition_test_path_is_symbolic_link(Condition *c) {
+static int condition_test_path_is_symbolic_link(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
return is_symlink(c->parameter) > 0;
}
-static int condition_test_path_is_mount_point(Condition *c) {
+static int condition_test_path_is_mount_point(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
return path_is_mount_point(c->parameter, NULL, AT_SYMLINK_FOLLOW) > 0;
}
-static int condition_test_path_is_read_write(Condition *c) {
+static int condition_test_path_is_read_write(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_READ_WRITE);
return path_is_read_only_fs(c->parameter) <= 0;
}
-static int condition_test_path_is_encrypted(Condition *c) {
+static int condition_test_path_is_encrypted(Condition *c, char **env) {
int r;
assert(c);
return r > 0;
}
-static int condition_test_directory_not_empty(Condition *c) {
+static int condition_test_directory_not_empty(Condition *c, char **env) {
int r;
assert(c);
return r <= 0 && r != -ENOENT;
}
-static int condition_test_file_not_empty(Condition *c) {
+static int condition_test_file_not_empty(Condition *c, char **env) {
struct stat st;
assert(c);
st.st_size > 0);
}
-static int condition_test_file_is_executable(Condition *c) {
+static int condition_test_file_is_executable(Condition *c, char **env) {
struct stat st;
assert(c);
(st.st_mode & 0111));
}
-static int condition_test_null(Condition *c) {
+static int condition_test_null(Condition *c, char **env) {
assert(c);
assert(c->type == CONDITION_NULL);
return true;
}
-int condition_test(Condition *c) {
+int condition_test(Condition *c, char **env) {
- static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
+ static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c, char **env) = {
[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_NULL] = condition_test_null,
[CONDITION_CPUS] = condition_test_cpus,
[CONDITION_MEMORY] = condition_test_memory,
+ [CONDITION_ENVIRONMENT] = condition_test_environment,
};
int r, b;
assert(c->type >= 0);
assert(c->type < _CONDITION_TYPE_MAX);
- r = condition_tests[c->type](c);
+ r = condition_tests[c->type](c, env);
if (r < 0) {
c->result = CONDITION_ERROR;
return r;
bool condition_test_list(
Condition *first,
+ char **env,
condition_to_string_t to_string,
condition_test_logger_t logger,
void *userdata) {
LIST_FOREACH(conditions, c, first) {
int r;
- r = condition_test(c);
+ r = condition_test(c, env);
if (logger) {
const char *p = c->type == CONDITION_NULL ? "true" : c->parameter;
[CONDITION_NULL] = "ConditionNull",
[CONDITION_CPUS] = "ConditionCPUs",
[CONDITION_MEMORY] = "ConditionMemory",
+ [CONDITION_ENVIRONMENT] = "ConditionEnvironment",
};
DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
[CONDITION_NULL] = "AssertNull",
[CONDITION_CPUS] = "AssertCPUs",
[CONDITION_MEMORY] = "AssertMemory",
+ [CONDITION_ENVIRONMENT] = "AssertEnvironment",
};
DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);