static void test_verbs(void) { static const Verb verbs[] = { { "help", VERB_ANY, VERB_ANY, 0, noop_dispatcher }, { "list-images", VERB_ANY, 1, 0, noop_dispatcher }, { "list", VERB_ANY, 2, VERB_DEFAULT, noop_dispatcher }, { "status", 2, VERB_ANY, 0, noop_dispatcher }, { "show", VERB_ANY, VERB_ANY, 0, noop_dispatcher }, { "terminate", 2, VERB_ANY, 0, noop_dispatcher }, { "login", 2, 2, 0, noop_dispatcher }, { "copy-to", 3, 4, 0, noop_dispatcher }, {} }; /* not found */ test_dispatch_one(STRV_MAKE("command-not-found"), verbs, -EINVAL); /* found */ test_dispatch_one(STRV_MAKE("show"), verbs, 0); /* found, too few args */ test_dispatch_one(STRV_MAKE("copy-to", "foo"), verbs, -EINVAL); /* found, meets min args */ test_dispatch_one(STRV_MAKE("status", "foo", "bar"), verbs, 0); /* found, too many args */ test_dispatch_one(STRV_MAKE("copy-to", "foo", "bar", "baz", "quux", "qaax"), verbs, -EINVAL); /* no verb, but a default is set */ test_dispatch_one(STRV_MAKE_EMPTY, verbs, 0); }
static void test_specifier_escape_strv(void) { test_specifier_escape_strv_one(NULL, NULL); test_specifier_escape_strv_one(STRV_MAKE(NULL), STRV_MAKE(NULL)); test_specifier_escape_strv_one(STRV_MAKE(""), STRV_MAKE("")); test_specifier_escape_strv_one(STRV_MAKE("foo"), STRV_MAKE("foo")); test_specifier_escape_strv_one(STRV_MAKE("%"), STRV_MAKE("%%")); test_specifier_escape_strv_one(STRV_MAKE("foo", "%", "foo%", "%foo", "foo%foo", "quux", "%%%"), STRV_MAKE("foo", "%%", "foo%%", "%%foo", "foo%%foo", "quux", "%%%%%%")); }
static void test_conf_files_insert(const char *root) { _cleanup_strv_free_ char **s = NULL; log_info("/* %s root=%s */", __func__, strempty(root)); char **dirs = STRV_MAKE("/dir1", "/dir2", "/dir3"); _cleanup_free_ const char *foo1 = prefix_root(root, "/dir1/foo.conf"), *foo2 = prefix_root(root, "/dir2/foo.conf"), *bar2 = prefix_root(root, "/dir2/bar.conf"), *zzz3 = prefix_root(root, "/dir3/zzz.conf"), *whatever = prefix_root(root, "/whatever.conf"); assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(foo2))); /* The same file again, https://github.com/systemd/systemd/issues/11124 */ assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(foo2))); /* Lower priority → new entry is ignored */ assert_se(conf_files_insert(&s, root, dirs, "/dir3/foo.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(foo2))); /* Higher priority → new entry replaces */ assert_se(conf_files_insert(&s, root, dirs, "/dir1/foo.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(foo1))); /* Earlier basename */ assert_se(conf_files_insert(&s, root, dirs, "/dir2/bar.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(bar2, foo1))); /* Later basename */ assert_se(conf_files_insert(&s, root, dirs, "/dir3/zzz.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3))); /* All lower priority → all ignored */ assert_se(conf_files_insert(&s, root, dirs, "/dir3/zzz.conf") == 0); assert_se(conf_files_insert(&s, root, dirs, "/dir2/bar.conf") == 0); assert_se(conf_files_insert(&s, root, dirs, "/dir3/bar.conf") == 0); assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3))); /* Two entries that don't match any of the directories, but match basename */ assert_se(conf_files_insert(&s, root, dirs, "/dir4/zzz.conf") == 0); assert_se(conf_files_insert(&s, root, dirs, "/zzz.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3))); /* An entry that doesn't match any of the directories, no match at all */ assert_se(conf_files_insert(&s, root, dirs, "/whatever.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, whatever, zzz3))); }
static void test_indirect(const char *root) { UnitFileChange *changes = NULL; unsigned n_changes = 0; UnitFileState state; const char *p; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); assert_se(write_string_file(p, "[Install]\n" "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system/indirectb.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); assert_se(symlink("indirecta.service", p) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; }
static int context_update_kernel_hostname(Context *c) { const char *static_hn; const char *hn; assert(c); static_hn = c->data[PROP_STATIC_HOSTNAME]; /* /etc/hostname with something other than "localhost" * has the highest preference ... */ if (hostname_is_useful(static_hn)) hn = static_hn; /* ... the transient host name, (ie: DHCP) comes next ... */ else if (!isempty(c->data[PROP_HOSTNAME])) hn = c->data[PROP_HOSTNAME]; /* ... fallback to static "localhost.*" ignored above ... */ else if (!isempty(static_hn)) hn = static_hn; /* ... and the ultimate fallback */ else hn = FALLBACK_HOSTNAME; if (sethostname_idempotent(hn) < 0) return -errno; (void) nscd_flush_cache(STRV_MAKE("hosts")); return 0; }
static void test_cat_files(void) { assert_se(cat_files("/no/such/file", NULL, 0) == -ENOENT); assert_se(cat_files("/no/such/file", NULL, CAT_FLAGS_MAIN_FILE_OPTIONAL) == 0); if (access("/etc/fstab", R_OK) >= 0) assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab"), 0) == 0); }
static int setup_test(Manager **m) { char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit", "directorynotempty", "makedirectory"); char **test_path; Manager *tmp = NULL; int r; assert_se(m); r = manager_new(MANAGER_USER, true, &tmp); if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { printf("Skipping test: manager_new: %s", strerror(-r)); return -EXIT_TEST_SKIP; } assert_se(r >= 0); assert_se(manager_startup(tmp, NULL, NULL) >= 0); STRV_FOREACH(test_path, tests_path) { _cleanup_free_ char *p = NULL; p = strjoin("/tmp/test-path_", *test_path, NULL); assert_se(p); (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL); }
static int setup_test(Manager **m) { char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit", "directorynotempty", "makedirectory"); char **test_path; Manager *tmp = NULL; int r; assert_se(m); r = enter_cgroup_subroot(); if (r == -ENOMEDIUM) { log_notice_errno(r, "Skipping test: cgroupfs not available"); return -EXIT_TEST_SKIP; } r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp); if (MANAGER_SKIP_TEST(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); return -EXIT_TEST_SKIP; } assert_se(r >= 0); assert_se(manager_startup(tmp, NULL, NULL) >= 0); STRV_FOREACH(test_path, tests_path) { _cleanup_free_ char *p = NULL; p = strjoin("/tmp/test-path_", *test_path); assert_se(p); (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL); }
static void test_add_dependency(const char *root) { UnitFileChange *changes = NULL; unsigned n_changes = 0; const char *p; p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target"); assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target"); assert_se(symlink("real-add-dependency-test-target.target", p) >= 0); p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service"); assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; }
static void test_copy_tree(void) { char original_dir[] = "/tmp/test-copy_tree/"; char copy_dir[] = "/tmp/test-copy_tree-copy/"; char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file"); char **links = STRV_MAKE("link", "file", "link2", "dir1/file"); char **p, **link; (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); STRV_FOREACH(p, files) { char *f = strjoina(original_dir, *p); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file") == 0); }
static void test_copy_tree(void) { char original_dir[] = "/tmp/test-copy_tree/"; char copy_dir[] = "/tmp/test-copy_tree-copy/"; char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file"); char **links = STRV_MAKE("link", "file", "link2", "dir1/file"); char **p, **link; rm_rf_dangerous(copy_dir, false, true, false); rm_rf_dangerous(original_dir, false, true, false); STRV_FOREACH(p, files) { char *f = strappenda(original_dir, *p); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file") == 0); }
static void test_verbs_no_default(void) { static const Verb verbs[] = { { "help", VERB_ANY, VERB_ANY, 0, noop_dispatcher }, {}, }; test_dispatch_one(STRV_MAKE(NULL), verbs, -EINVAL); }
static int spawn_curl(const char* url) { char **argv = STRV_MAKE("curl", "-HAccept: application/vnd.fdo.journal", "--silent", "--show-error", url); int r; r = spawn_child("curl", argv); if (r < 0) log_error_errno(errno, "Failed to spawn curl: %m"); return r; }
static int determine_matches(const char *image, char **l, bool allow_any, char ***ret) { _cleanup_strv_free_ char **k = NULL; int r; /* Determine the matches to apply. If the list is empty we derive the match from the image name. If the list * contains exactly the "-" we return a wildcard list (which is the empty list), but only if this is expressly * permitted. */ if (strv_isempty(l)) { char *prefix; r = extract_prefix(image, &prefix); if (r < 0) return log_error_errno(r, "Failed to extract prefix of image name '%s': %m", image); if (!arg_quiet) log_info("(Matching unit files with prefix '%s'.)", prefix); r = strv_consume(&k, prefix); if (r < 0) return log_oom(); } else if (strv_equal(l, STRV_MAKE("-"))) { if (!allow_any) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Refusing all unit file match."); if (!arg_quiet) log_info("(Matching all unit files.)"); } else { k = strv_copy(l); if (!k) return log_oom(); if (!arg_quiet) { _cleanup_free_ char *joined = NULL; joined = strv_join(k, "', '"); if (!joined) return log_oom(); log_info("(Matching unit files with prefixes '%s'.)", joined); } } *ret = TAKE_PTR(k); return 0; }
static int test_policy_load(Policy *p, const char *name) { _cleanup_free_ char *path = NULL; int r = 0; path = strjoin(TEST_DIR, "/bus-policy/", name, NULL); assert_se(path); if (access(path, R_OK) == 0) r = policy_load(p, STRV_MAKE(path)); else r = -ENOENT; return r; }
static void test_copy_tree(void) { char original_dir[] = "/tmp/test-copy_tree/"; char copy_dir[] = "/tmp/test-copy_tree-copy/"; char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file"); char **links = STRV_MAKE("link", "file", "link2", "dir1/file"); char **p, **link; const char *unixsockp; struct stat st; log_info("%s", __func__); (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); STRV_FOREACH(p, files) { _cleanup_free_ char *f; assert_se(f = strappend(original_dir, *p)); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0); }
static void test_foreach_word_quoted(void) { check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", STRV_MAKE("test", "a", "b", "c", "d", "e", "", "", "hhh", "", "", "a b c"), false); check("test \"xxx", STRV_MAKE("test"), true); check("test\\", STRV_MAKE_EMPTY, true); }
static int show_policy(const char *fn) { Policy p = {}; int r; r = policy_load(&p, STRV_MAKE(fn)); if (r < 0) { log_error_errno(r, "Failed to load policy %s: %m", fn); return r; } policy_dump(&p); policy_free(&p); return 0; }
static int process_keymap(void) { const char *etc_vconsoleconf; char **keymap; int r; etc_vconsoleconf = prefix_roota(arg_root, "/etc/vconsole.conf"); if (laccess(etc_vconsoleconf, F_OK) >= 0) return 0; if (arg_copy_keymap && arg_root) { mkdir_parents(etc_vconsoleconf, 0755); r = copy_file("/etc/vconsole.conf", etc_vconsoleconf, 0, 0644, 0, COPY_REFLINK); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to copy %s: %m", etc_vconsoleconf); log_info("%s copied.", etc_vconsoleconf); return 0; } } r = prompt_keymap(); if (r == -ENOENT) return 0; /* don't fail if no keymaps are installed */ if (r < 0) return r; if (isempty(arg_keymap)) return 0; keymap = STRV_MAKE(strjoina("KEYMAP=", arg_keymap)); r = mkdir_parents(etc_vconsoleconf, 0755); if (r < 0) return log_error_errno(r, "Failed to create the parent directory of %s: %m", etc_vconsoleconf); r = write_env_file(etc_vconsoleconf, keymap); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_vconsoleconf); log_info("%s written.", etc_vconsoleconf); return 0; }
static void test_cg_get_keyed_attribute(void) { _cleanup_free_ char *val = NULL; char *vals3[3] = {}, *vals3a[3] = {}; int i, r; r = cg_get_keyed_attribute("cpu", "/init.scope", "no_such_file", STRV_MAKE("no_such_attr"), &val); if (r == -ENOMEDIUM) { log_info_errno(r, "Skipping most of %s, /sys/fs/cgroup not accessible: %m", __func__); return; } assert_se(r == -ENOENT); assert_se(val == NULL); if (access("/sys/fs/cgroup/init.scope/cpu.stat", R_OK) < 0) { log_info_errno(errno, "Skipping most of %s, /init.scope/cpu.stat not accessible: %m", __func__); return; } assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == -ENXIO); assert_se(val == NULL); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 0); log_info("cpu /init.scope cpu.stat [usage_usec] → \"%s\"", val); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == -ENXIO); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == -ENXIO); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0); log_info("cpu /init.scope cpu.stat [usage_usec user_usec system_usec] → \"%s\", \"%s\", \"%s\"", vals3[0], vals3[1], vals3[2]); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0); log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"", vals3a[0], vals3a[1], vals3a[2]); for (i = 0; i < 3; i++) { free(vals3[i]); free(vals3a[i]); } }
static int setup_test(Manager **m) { char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit", "directorynotempty", "makedirectory"); char **test_path; Manager *tmp; int r; assert_se(m); r = manager_new(SYSTEMD_USER, true, &tmp); if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { printf("Skipping test: manager_new: %s", strerror(-r)); return -EXIT_TEST_SKIP; } assert_se(r >= 0); assert_se(manager_startup(tmp, NULL, NULL) >= 0); STRV_FOREACH(test_path, tests_path) { rm_rf_dangerous(strappenda("/tmp/test-path_", *test_path), false, true, false); }
int main(int argc, char *argv[]) { _cleanup_hashmap_free_free_ Hashmap *pids = NULL; _cleanup_endmntent_ FILE *f = NULL; struct mntent* me; int r; if (argc > 1) { log_error("This program takes no argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); f = setmntent("/etc/fstab", "r"); if (!f) { if (errno == ENOENT) { r = 0; goto finish; } r = log_error_errno(errno, "Failed to open /etc/fstab: %m"); goto finish; } pids = hashmap_new(NULL); if (!pids) { r = log_oom(); goto finish; } while ((me = getmntent(f))) { pid_t pid; int k; char *s; /* Remount the root fs, /usr and all API VFS */ if (!mount_point_is_api(me->mnt_dir) && !path_equal(me->mnt_dir, "/") && !path_equal(me->mnt_dir, "/usr")) continue; log_debug("Remounting %s", me->mnt_dir); pid = fork(); if (pid < 0) { r = log_error_errno(errno, "Failed to fork: %m"); goto finish; } if (pid == 0) { /* Child */ (void) reset_all_signal_handlers(); (void) reset_signal_mask(); (void) prctl(PR_SET_PDEATHSIG, SIGTERM); execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount")); log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m"); _exit(EXIT_FAILURE); } /* Parent */ s = strdup(me->mnt_dir); if (!s) { r = log_oom(); goto finish; } k = hashmap_put(pids, PID_TO_PTR(pid), s); if (k < 0) { free(s); r = log_oom(); goto finish; } } r = 0; while (!hashmap_isempty(pids)) { siginfo_t si = {}; char *s; if (waitid(P_ALL, 0, &si, WEXITED) < 0) { if (errno == EINTR) continue; r = log_error_errno(errno, "waitid() failed: %m"); goto finish; } s = hashmap_remove(pids, PID_TO_PTR(si.si_pid)); if (s) { if (!is_clean_exit(si.si_code, si.si_status, EXIT_CLEAN_COMMAND, NULL)) { if (si.si_code == CLD_EXITED) log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status); else log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status)); r = -ENOEXEC; } free(s); } } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static void test_config_parse_strv(void) { test_config_parse_strv_one("", STRV_MAKE_EMPTY); test_config_parse_strv_one("foo", STRV_MAKE("foo")); test_config_parse_strv_one("foo bar foo", STRV_MAKE("foo", "bar", "foo")); test_config_parse_strv_one("\"foo bar\" foo", STRV_MAKE("foo bar", "foo")); }
static void test_preset_and_list(const char *root) { UnitFileChange *changes = NULL; unsigned n_changes = 0, i; const char *p, *q; UnitFileState state; bool got_yes = false, got_no = false; Iterator j; UnitFileList *fl; Hashmap *h; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); assert_se(write_string_file(p, "enable *-yes.*\n" "disable *\n", WRITE_STRING_FILE_CREATE) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes > 0); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); for (i = 0; i < n_changes; i++) { if (changes[i].type == UNIT_FILE_SYMLINK) { assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); assert_se(streq(changes[i].path, p)); } else assert_se(changes[i].type == UNIT_FILE_UNLINK); } unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(h = hashmap_new(&string_hash_ops)); assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0); p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); HASHMAP_FOREACH(fl, h, j) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); assert_se(fl->state == state); if (streq(fl->path, p)) { got_yes = true; assert_se(fl->state == UNIT_FILE_ENABLED); } else if (streq(fl->path, q)) { got_no = true; assert_se(fl->state == UNIT_FILE_DISABLED); } else assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT)); }
r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); log_error("disable files2"); changes = NULL; n_changes = 0; r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); log_error("link files2"); changes = NULL; n_changes = 0; r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); assert_se(r >= 0);
static void test_template_enable(const char *root) { UnitFileChange *changes = NULL; unsigned n_changes = 0; UnitFileState state; const char *p; log_info("== %s ==", __func__); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/[email protected]"); assert_se(write_string_file(p, "[Install]\n" "DefaultInstance=def\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/usr/lib/systemd/system/[email protected]"); assert_se(symlink("[email protected]", p) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); log_info("== %s with [email protected] enabled ==", __func__); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("[email protected]"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/[email protected]")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/[email protected]"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("[email protected]"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); log_info("== %s with [email protected] enabled ==", __func__); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("*****@*****.**"), &changes, &n_changes) >= 0); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/[email protected]")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/[email protected]"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("*****@*****.**"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); log_info("== %s with [email protected] enabled ==", __func__); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("*****@*****.**"), &changes, &n_changes) >= 0); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/[email protected]")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/[email protected]"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "[email protected]", &state) >= 0 && state == UNIT_FILE_INDIRECT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "*****@*****.**", &state) >= 0 && state == UNIT_FILE_ENABLED); }
static void test_basic_mask_and_enable(const char *root) { const char *p; UnitFileState state; UnitFileChange *changes = NULL; unsigned n_changes = 0; log_set_max_level(LOG_DEBUG); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/a.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/b.service"); assert_se(symlink("a.service", p) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/c.service"); assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/d.service"); assert_se(symlink("c.service", p) >= 0); /* This one is interesting, as d follows a relative, then an absolute symlink */ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/dev/null")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); /* Enabling a masked unit should fail! */ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* Enabling it again should succeed but be a NOP */ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); /* Disabling a disabled unit must suceed but be a NOP */ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; /* Let's enable this indirectly via a symlink */ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* Let's try to reenable */ assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); assert_se(changes[1].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); assert_se(streq(changes[1].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); }
static void test_linked_units(const char *root) { const char *p, *q; UnitFileState state; UnitFileChange *changes = NULL; unsigned n_changes = 0, i; /* * We'll test three cases here: * * a) a unit file in /opt, that we use "systemctl link" and * "systemctl enable" on to make it available to the system * * b) a unit file in /opt, that is statically linked into * /usr/lib/systemd/system, that "enable" should work on * correctly. * * c) a unit file in /opt, that is linked into * /etc/systemd/system, and where "enable" should result in * -ELOOP, since using information from /etc to generate * information in /etc should not be allowed. */ p = strjoina(root, "/opt/linked.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/opt/linked2.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); p = strjoina(root, "/opt/linked3.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); assert_se(symlink("/opt/linked2.service", p) >= 0); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service"); assert_se(symlink("/opt/linked3.service", p) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); /* First, let's link the unit into the search path */ assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/opt/linked.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); /* Let's unlink it from the search path again */ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); /* Now, let's not just link it, but also enable it */ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); for (i = 0 ; i < n_changes; i++) { assert_se(changes[i].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[i].source, "/opt/linked.service")); if (p && streq(changes[i].path, p)) p = NULL; else if (q && streq(changes[i].path, q)) q = NULL; else assert_not_reached("wut?"); } assert(!p && !q); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* And let's unlink it again */ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); for (i = 0; i < n_changes; i++) { assert_se(changes[i].type == UNIT_FILE_UNLINK); if (p && streq(changes[i].path, p)) p = NULL; else if (q && streq(changes[i].path, q)) q = NULL; else assert_not_reached("wut?"); } assert(!p && !q); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); for (i = 0 ; i < n_changes; i++) { assert_se(changes[i].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[i].source, "/opt/linked2.service")); if (p && streq(changes[i].path, p)) p = NULL; else if (q && streq(changes[i].path, q)) q = NULL; else assert_not_reached("wut?"); } assert(!p && !q); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(startswith(changes[0].path, root)); assert_se(endswith(changes[0].path, "linked3.service")); assert_se(streq(changes[0].source, "/opt/linked3.service")); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; }
static int process( const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration, Group **ret) { Group *g; int r, all_unified; assert(controller); assert(path); assert(a); all_unified = cg_all_unified(); if (all_unified < 0) return all_unified; g = hashmap_get(a, path); if (!g) { g = hashmap_get(b, path); if (!g) { g = new0(Group, 1); if (!g) return -ENOMEM; g->path = strdup(path); if (!g->path) { group_free(g); return -ENOMEM; } r = hashmap_put(a, g->path, g); if (r < 0) { group_free(g); return r; } } else { r = hashmap_move_one(a, b, path); if (r < 0) return r; g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false; } } if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) { _cleanup_fclose_ FILE *f = NULL; pid_t pid; r = cg_enumerate_processes(controller, path, &f); if (r == -ENOENT) return 0; if (r < 0) return r; g->n_tasks = 0; while (cg_read_pid(f, &pid) > 0) { if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0) continue; g->n_tasks++; } if (g->n_tasks > 0) g->n_tasks_valid = true; } else if (streq(controller, "pids") && arg_count == COUNT_PIDS) { if (is_root_cgroup(path)) { r = procfs_tasks_get_current(&g->n_tasks); if (r < 0) return r; } else { _cleanup_free_ char *p = NULL, *v = NULL; r = cg_get_path(controller, path, "pids.current", &p); if (r < 0) return r; r = read_one_line_file(p, &v); if (r == -ENOENT) return 0; if (r < 0) return r; r = safe_atou64(v, &g->n_tasks); if (r < 0) return r; } if (g->n_tasks > 0) g->n_tasks_valid = true; } else if (STR_IN_SET(controller, "cpu", "cpuacct")) { _cleanup_free_ char *p = NULL, *v = NULL; uint64_t new_usage; nsec_t timestamp; if (is_root_cgroup(path)) { r = procfs_cpu_get_usage(&new_usage); if (r < 0) return r; } else if (all_unified) { _cleanup_free_ char *val = NULL; if (!streq(controller, "cpu")) return 0; r = cg_get_keyed_attribute("cpu", path, "cpu.stat", STRV_MAKE("usage_usec"), &val); if (IN_SET(r, -ENOENT, -ENXIO)) return 0; if (r < 0) return r; r = safe_atou64(val, &new_usage); if (r < 0) return r; new_usage *= NSEC_PER_USEC; } else { if (!streq(controller, "cpuacct")) return 0; r = cg_get_path(controller, path, "cpuacct.usage", &p); if (r < 0) return r; r = read_one_line_file(p, &v); if (r == -ENOENT) return 0; if (r < 0) return r; r = safe_atou64(v, &new_usage); if (r < 0) return r; } timestamp = now_nsec(CLOCK_MONOTONIC); if (g->cpu_iteration == iteration - 1 && (nsec_t) new_usage > g->cpu_usage) { nsec_t x, y; x = timestamp - g->cpu_timestamp; if (x < 1) x = 1; y = (nsec_t) new_usage - g->cpu_usage; g->cpu_fraction = (double) y / (double) x; g->cpu_valid = true; } g->cpu_usage = (nsec_t) new_usage; g->cpu_timestamp = timestamp; g->cpu_iteration = iteration; } else if (streq(controller, "memory")) { if (is_root_cgroup(path)) { r = procfs_memory_get_current(&g->memory); if (r < 0) return r; } else { _cleanup_free_ char *p = NULL, *v = NULL; if (all_unified) r = cg_get_path(controller, path, "memory.current", &p); else r = cg_get_path(controller, path, "memory.usage_in_bytes", &p); if (r < 0) return r; r = read_one_line_file(p, &v); if (r == -ENOENT) return 0; if (r < 0) return r; r = safe_atou64(v, &g->memory); if (r < 0) return r; } if (g->memory > 0) g->memory_valid = true; } else if ((streq(controller, "io") && all_unified) || (streq(controller, "blkio") && !all_unified)) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; uint64_t wr = 0, rd = 0; nsec_t timestamp; r = cg_get_path(controller, path, all_unified ? "io.stat" : "blkio.io_service_bytes", &p); if (r < 0) return r; f = fopen(p, "re"); if (!f) { if (errno == ENOENT) return 0; return -errno; } for (;;) { char line[LINE_MAX], *l; uint64_t k, *q; if (!fgets(line, sizeof(line), f)) break; /* Trim and skip the device */ l = strstrip(line); l += strcspn(l, WHITESPACE); l += strspn(l, WHITESPACE); if (all_unified) { while (!isempty(l)) { if (sscanf(l, "rbytes=%" SCNu64, &k)) rd += k; else if (sscanf(l, "wbytes=%" SCNu64, &k)) wr += k; l += strcspn(l, WHITESPACE); l += strspn(l, WHITESPACE); } } else { if (first_word(l, "Read")) { l += 4; q = &rd; } else if (first_word(l, "Write")) { l += 5; q = ≀ } else continue; l += strspn(l, WHITESPACE); r = safe_atou64(l, &k); if (r < 0) continue; *q += k; } } timestamp = now_nsec(CLOCK_MONOTONIC); if (g->io_iteration == iteration - 1) { uint64_t x, yr, yw; x = (uint64_t) (timestamp - g->io_timestamp); if (x < 1) x = 1; if (rd > g->io_input) yr = rd - g->io_input; else yr = 0; if (wr > g->io_output) yw = wr - g->io_output; else yw = 0; if (yr > 0 || yw > 0) { g->io_input_bps = (yr * 1000000000ULL) / x; g->io_output_bps = (yw * 1000000000ULL) / x; g->io_valid = true; } } g->io_input = rd; g->io_output = wr; g->io_timestamp = timestamp; g->io_iteration = iteration; } if (ret) *ret = g; return 0; }