diff options
author | Adrian Szyndela <adrian.s@samsung.com> | 2020-03-27 09:27:11 +0100 |
---|---|---|
committer | Adrian Szyndela <adrian.s@samsung.com> | 2020-03-27 11:13:45 +0100 |
commit | 5f3f628ebc0867b7d078849c614958e09ce74850 (patch) | |
tree | e6cabc7e68ae658b13db8857d3c308de691f73db /src/test | |
parent | 31e58df2dbd9a3b2afcebd654cc1ad29589dd6c0 (diff) | |
parent | efb536d0cbe2e58f80e501d19999928c75e08f6a (diff) | |
download | systemd-5f3f628ebc0867b7d078849c614958e09ce74850.tar.gz systemd-5f3f628ebc0867b7d078849c614958e09ce74850.tar.bz2 systemd-5f3f628ebc0867b7d078849c614958e09ce74850.zip |
Merge v243 into tizen
systemd v243
Diffstat (limited to 'src/test')
64 files changed, 3219 insertions, 1421 deletions
diff --git a/src/test/generate-sym-test.py b/src/test/generate-sym-test.py index 357cce8e44..4d358b8e34 100755 --- a/src/test/generate-sym-test.py +++ b/src/test/generate-sym-test.py @@ -6,18 +6,22 @@ for header in sys.argv[2:]: print('#include "{}"'.format(header.split('/')[-1])) print(''' -void* functions[] = {''') +const void* symbols[] = {''') for line in open(sys.argv[1]): match = re.search('^ +([a-zA-Z0-9_]+);', line) if match: - print(' {},'.format(match.group(1))) + s = match.group(1) + if s == 'sd_bus_object_vtable_format': + print(' &{},'.format(s)) + else: + print(' {},'.format(s)) print('''}; int main(void) { unsigned i; - for (i = 0; i < sizeof(functions)/sizeof(void*); i++) - printf("%p\\n", functions[i]); + for (i = 0; i < sizeof(symbols)/sizeof(void*); i++) + printf("%p\\n", symbols[i]); return 0; }''') diff --git a/src/test/meson.build b/src/test/meson.build index 660febccaa..7709993c05 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -137,6 +137,10 @@ tests += [ [], 'ENABLE_EFI'], + [['src/test/test-unit-file.c'], + [], + []], + [['src/test/test-unit-name.c', 'src/test/test-helper.c'], [libcore, @@ -148,7 +152,7 @@ tests += [ libmount, libblkid]], - [['src/test/test-unit-file.c', + [['src/test/test-load-fragment.c', 'src/test/test-helper.c'], [libcore, libshared], @@ -216,6 +220,10 @@ tests += [ [], []], + [['src/test/test-format-util.c'], + [], + []], + [['src/test/test-ratelimit.c'], [], []], @@ -269,6 +277,10 @@ tests += [ [], []], + [['src/test/test-umask-util.c'], + [], + []], + [['src/test/test-proc-cmdline.c'], [], []], @@ -297,6 +309,10 @@ tests += [ [], []], + [['src/test/test-exit-status.c'], + [], + []], + [['src/test/test-specifier.c'], [], []], @@ -574,6 +590,12 @@ tests += [ libshared], []], + [['src/test/test-cgroup-unit-default.c', + 'src/test/test-helper.c'], + [libcore, + libshared], + []], + [['src/test/test-cgroup-mask.c', 'src/test/test-helper.c'], [libcore, @@ -585,10 +607,18 @@ tests += [ libmount, libblkid]], + [['src/test/test-varlink.c'], + [], + [threads]], + [['src/test/test-cgroup-util.c'], [], []], + [['src/test/test-env-file.c'], + [], + []], + [['src/test/test-env-util.c'], [], []], @@ -605,6 +635,11 @@ tests += [ [], []], + [['src/test/test-chase-symlinks.c'], + [], + [], + '', 'manual'], + [['src/test/test-path.c', 'src/test/test-helper.c'], [libcore, @@ -732,6 +767,10 @@ tests += [ [['src/test/test-sd-hwdb.c'], [], []], + + [['src/test/test-local-addresses.c'], + [], + []], ] ############################################################ @@ -905,7 +944,8 @@ tests += [ [], [threads]], - [['src/libsystemd/sd-bus/test-bus-vtable.c'], + [['src/libsystemd/sd-bus/test-bus-vtable.c', + 'src/libsystemd/sd-bus/test-vtable-data.h'], [], []], @@ -939,7 +979,8 @@ tests += [ [], []], - [['src/libsystemd/sd-bus/test-bus-introspect.c'], + [['src/libsystemd/sd-bus/test-bus-introspect.c', + 'src/libsystemd/sd-bus/test-vtable-data.h'], [], []], @@ -951,10 +992,6 @@ tests += [ [], []], - [['src/libsystemd/sd-netlink/test-local-addresses.c'], - [], - []], - [['src/libsystemd/sd-resolve/test-resolve.c'], [], [threads], @@ -986,7 +1023,10 @@ tests += [ ] -if cxx_cmd != '' +# test-bus-vtable-cc.cc is a symlink and symlinks get lost in containers on FuzzBuzz. +# The issue has been reported to the developers of FuzzBuzz and hopefully will be fixed soon. +# In the meantime, let's just skip the symlink there. +if cxx_cmd != '' and not want_fuzzbuzz tests += [ [['src/libsystemd/sd-bus/test-bus-vtable-cc.cc'], [], diff --git a/src/test/test-alloc-util.c b/src/test/test-alloc-util.c index ad10eb178a..758b753237 100644 --- a/src/test/test-alloc-util.c +++ b/src/test/test-alloc-util.c @@ -1,10 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <malloc.h> #include <stdint.h> #include "alloc-util.h" #include "macro.h" #include "memory-util.h" +#include "random-util.h" +#include "tests.h" static void test_alloca(void) { static const uint8_t zero[997] = { }; @@ -21,38 +24,52 @@ static void test_alloca(void) { static void test_GREEDY_REALLOC(void) { _cleanup_free_ int *a = NULL, *b = NULL; - size_t n_allocated = 0, i; + size_t n_allocated = 0, i, j; - /* Give valgrind a chance to verify our realloc operations */ + /* Give valgrind a chance to verify our realloc() operations */ - for (i = 0; i < 2048; i++) { + for (i = 0; i < 20480; i++) { assert_se(GREEDY_REALLOC(a, n_allocated, i + 1)); - a[i] = i; + assert_se(n_allocated >= i + 1); + assert_se(malloc_usable_size(a) >= (i + 1) * sizeof(int)); + a[i] = (int) i; assert_se(GREEDY_REALLOC(a, n_allocated, i / 2)); + assert_se(n_allocated >= i / 2); + assert_se(malloc_usable_size(a) >= (i / 2) * sizeof(int)); } - for (i = 30, n_allocated = 0; i < 2048; i+=7) { + for (j = 0; j < i / 2; j++) + assert_se(a[j] == (int) j); + + for (i = 30, n_allocated = 0; i < 20480; i += 7) { assert_se(GREEDY_REALLOC(b, n_allocated, i + 1)); - b[i] = i; + assert_se(n_allocated >= i + 1); + assert_se(malloc_usable_size(b) >= (i + 1) * sizeof(int)); + b[i] = (int) i; assert_se(GREEDY_REALLOC(b, n_allocated, i / 2)); + assert_se(n_allocated >= i / 2); + assert_se(malloc_usable_size(b) >= (i / 2) * sizeof(int)); } + + for (j = 30; j < i / 2; j += 7) + assert_se(b[j] == (int) j); } static void test_memdup_multiply_and_greedy_realloc(void) { - int org[] = {1, 2, 3}; + static const int org[] = { 1, 2, 3 }; _cleanup_free_ int *dup; int *p; size_t i, allocated = 3; - dup = (int*) memdup_suffix0_multiply(org, sizeof(int), 3); + dup = memdup_suffix0_multiply(org, sizeof(int), 3); assert_se(dup); assert_se(dup[0] == 1); assert_se(dup[1] == 2); assert_se(dup[2] == 3); - assert_se(*(uint8_t*) (dup + 3) == (uint8_t) 0); + assert_se(((uint8_t*) dup)[sizeof(int) * 3] == 0); free(dup); - dup = (int*) memdup_multiply(org, sizeof(int), 3); + dup = memdup_multiply(org, sizeof(int), 3); assert_se(dup); assert_se(dup[0] == 1); assert_se(dup[1] == 2); @@ -91,11 +108,54 @@ static void test_bool_assign(void) { assert(!h); } +static int cleanup_counter = 0; + +static void cleanup1(void *a) { + log_info("%s(%p)", __func__, a); + assert_se(++cleanup_counter == *(int*) a); +} +static void cleanup2(void *a) { + log_info("%s(%p)", __func__, a); + assert_se(++cleanup_counter == *(int*) a); +} +static void cleanup3(void *a) { + log_info("%s(%p)", __func__, a); + assert_se(++cleanup_counter == *(int*) a); +} + +static void test_cleanup_order(void) { + _cleanup_(cleanup1) int x1 = 4, x2 = 3; + _cleanup_(cleanup3) int z = 2; + _cleanup_(cleanup2) int y = 1; + log_debug("x1: %p", &x1); + log_debug("x2: %p", &x2); + log_debug("y: %p", &y); + log_debug("z: %p", &z); +} + +static void test_auto_erase_memory(void) { + _cleanup_(erase_and_freep) uint8_t *p1, *p2; + + assert_se(p1 = new(uint8_t, 1024)); + assert_se(p2 = new(uint8_t, 1024)); + + assert_se(genuine_random_bytes(p1, 1024, RANDOM_BLOCK) == 0); + + /* before we exit the scope, do something with this data, so that the compiler won't optimize this away */ + memcpy(p2, p1, 1024); + for (size_t i = 0; i < 1024; i++) + assert_se(p1[i] == p2[i]); +} + int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + test_alloca(); test_GREEDY_REALLOC(); test_memdup_multiply_and_greedy_realloc(); test_bool_assign(); + test_cleanup_order(); + test_auto_erase_memory(); return 0; } diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c index 23b06be19b..fa91869cf5 100644 --- a/src/test/test-ask-password-api.c +++ b/src/test/test-ask-password-api.c @@ -20,4 +20,5 @@ int main(int argc, char **argv) { log_parse_environment(); ask_password(); + return EXIT_SUCCESS; } diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c index 6a0bf1462f..6a75221542 100644 --- a/src/test/test-bpf.c +++ b/src/test/test-bpf.c @@ -9,11 +9,13 @@ #include "bpf-program.h" #include "load-fragment.h" #include "manager.h" +#include "missing.h" #include "rm-rf.h" #include "service.h" #include "test-helper.h" #include "tests.h" #include "unit.h" +#include "virt.h" /* We use the same limit here that PID 1 bumps RLIMIT_MEMLOCK to if it can */ #define CAN_MEMLOCK_SIZE (64U*1024U*1024U) @@ -41,7 +43,7 @@ static bool can_memlock(void) { int main(int argc, char *argv[]) { struct bpf_insn exit_insn[] = { - BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_MOV64_IMM(BPF_REG_0, 0), /* drop */ BPF_EXIT_INSN() }; @@ -53,11 +55,14 @@ int main(int argc, char *argv[]) { char log_buf[65535]; struct rlimit rl; int r; + union bpf_attr attr; + bool test_custom_filter = false; + const char *test_prog = "/sys/fs/bpf/test-dropper"; test_setup_logging(LOG_DEBUG); - if (is_run_on_travis_ci()) - return log_tests_skipped("test-bpf fails on Travis CI: https://github.com/systemd/systemd/issues/9666"); + if (detect_container() > 0) + return log_tests_skipped("test-bpf fails inside LXC and Docker containers: https://github.com/systemd/systemd/issues/9666"); assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0); rl.rlim_cur = rl.rlim_max = MAX3(rl.rlim_cur, rl.rlim_max, CAN_MEMLOCK_SIZE); @@ -87,17 +92,34 @@ int main(int argc, char *argv[]) { return log_tests_skipped("BPF firewalling not supported"); assert_se(r > 0); - if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI) + if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI) { log_notice("BPF firewalling with BPF_F_ALLOW_MULTI supported. Yay!"); - else + test_custom_filter = true; + } else log_notice("BPF firewalling (though without BPF_F_ALLOW_MULTI) supported. Good."); r = bpf_program_load_kernel(p, log_buf, ELEMENTSOF(log_buf)); assert(r >= 0); + if (test_custom_filter) { + attr = (union bpf_attr) { + .pathname = PTR_TO_UINT64(test_prog), + .bpf_fd = p->kernel_fd, + .file_flags = 0, + }; + + (void) unlink(test_prog); + + r = bpf(BPF_OBJ_PIN, &attr, sizeof(attr)); + if (r < 0) { + log_warning_errno(errno, "BPF object pinning failed, will not run custom filter test: %m"); + test_custom_filter = false; + } + } + p = bpf_program_unref(p); - /* The simple tests suceeded. Now let's try full unit-based use-case. */ + /* The simple tests succeeded. Now let's try full unit-based use-case. */ assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); @@ -174,5 +196,31 @@ int main(int argc, char *argv[]) { assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED || SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS); + if (test_custom_filter) { + assert_se(u = unit_new(m, sizeof(Service))); + assert_se(unit_add_name(u, "custom-filter.service") == 0); + assert_se(cc = unit_get_cgroup_context(u)); + u->perpetual = true; + + cc->ip_accounting = true; + + assert_se(config_parse_ip_filter_bpf_progs(u->id, "filename", 1, "Service", 1, "IPIngressFilterPath", 0, test_prog, &cc->ip_filters_ingress, u) == 0); + assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "-/bin/ping -c 1 127.0.0.1 -W 5", SERVICE(u)->exec_command, u) == 0); + + SERVICE(u)->type = SERVICE_ONESHOT; + u->load_state = UNIT_LOADED; + + assert_se(unit_start(u) >= 0); + + while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED)) + assert_se(sd_event_run(m->event, UINT64_MAX) >= 0); + + assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code != CLD_EXITED || + SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status != EXIT_SUCCESS); + + (void) unlink(test_prog); + assert_se(SERVICE(u)->state == SERVICE_DEAD); + } + return 0; } diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index 5e5638cd72..5bd0e3458c 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -5,8 +5,8 @@ #include "btrfs-util.h" #include "fd-util.h" #include "fileio.h" +#include "format-util.h" #include "log.h" -#include "parse-util.h" #include "string-util.h" #include "util.h" diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 10c9f63b9b..46358ef952 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "calendarspec.h" +#include "errno-util.h" #include "string-util.h" #include "util.h" @@ -23,7 +24,7 @@ static void test_one(const char *input, const char *output) { u = now(CLOCK_REALTIME); r = calendar_spec_next_usec(c, u, &u); - printf("Next: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u)); + printf("Next: %s\n", r < 0 ? strerror_safe(r) : format_timestamp(buf, sizeof(buf), u)); calendar_spec_free(c); assert_se(calendar_spec_from_string(p, &c) >= 0); @@ -56,7 +57,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ u = after; r = calendar_spec_next_usec(c, after, &u); - printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof buf, u)); + printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u)); if (expect != (usec_t)-1) assert_se(r >= 0 && u == expect); else @@ -103,10 +104,10 @@ static void test_hourly_bug_4031(void) { assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0); printf("Now: %s (%"PRIu64")\n", format_timestamp_us(buf, sizeof buf, n), n); - printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof buf, u), u); + printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u), u); assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0); - printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror(-r) : format_timestamp_us(zaf, sizeof zaf, w), w); + printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(zaf, sizeof zaf, w), w); assert_se(n < u); assert_se(u <= n + USEC_PER_HOUR); diff --git a/src/test/test-capability.c b/src/test/test-capability.c index 6b2de66bb7..f9fae84dde 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -99,7 +99,7 @@ static int setup_tests(bool *run_ambient) { nobody = getpwnam(NOBODY_USER_NAME); if (!nobody) - return log_error_errno(errno, "Could not find nobody user: %m"); + return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Could not find nobody user: %m"); test_uid = nobody->pw_uid; test_gid = nobody->pw_gid; diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 7f6c0c2772..72a6551ffd 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -59,7 +59,6 @@ static int test_cgroup_mask(void) { m->default_tasks_accounting = false; m->default_tasks_max = (uint64_t) -1; - assert_se(r >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); /* Load units and verify hierarchy. */ diff --git a/src/test/test-cgroup-unit-default.c b/src/test/test-cgroup-unit-default.c new file mode 100644 index 0000000000..4fb629217f --- /dev/null +++ b/src/test/test-cgroup-unit-default.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <stdio.h> + +#include "cgroup.h" +#include "manager.h" +#include "rm-rf.h" +#include "test-helper.h" +#include "tests.h" +#include "unit.h" + +static int test_default_memory_low(void) { + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; + _cleanup_(manager_freep) Manager *m = NULL; + Unit *root, *dml, + *dml_passthrough, *dml_passthrough_empty, *dml_passthrough_set_dml, *dml_passthrough_set_ml, + *dml_override, *dml_override_empty, + *dml_discard, *dml_discard_empty, *dml_discard_set_ml; + uint64_t dml_tree_default; + int r; + + r = enter_cgroup_subroot(); + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); + + assert_se(set_unit_path(get_testdata_dir()) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); + if (IN_SET(r, -EPERM, -EACCES)) { + log_error_errno(r, "manager_new: %m"); + return log_tests_skipped("cannot create manager"); + } + + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + /* dml.slice has DefaultMemoryLow=50. Beyond that, individual subhierarchies look like this: + * + * 1. dml-passthrough.slice sets MemoryLow=100. This should not affect its children, as only + * DefaultMemoryLow is propagated, not MemoryLow. As such, all leaf services should end up with + * memory.low as 50, inherited from dml.slice, *except* for dml-passthrough-set-ml.service, which + * should have the value of 0, as it has MemoryLow explicitly set. + * + * ┌───────────┐ + * │ dml.slice │ + * └─────┬─────┘ + * MemoryLow=100 + * ┌───────────┴───────────┐ + * │ dml-passthrough.slice │ + * └───────────┬───────────┘ + * ┌───────────────────────────────────┼───────────────────────────────────┐ + * no new settings DefaultMemoryLow=15 MemoryLow=0 + * ┌───────────────┴───────────────┐ ┌────────────────┴────────────────┐ ┌───────────────┴────────────────┐ + * │ dml-passthrough-empty.service │ │ dml-passthrough-set-dml.service │ │ dml-passthrough-set-ml.service │ + * └───────────────────────────────┘ └─────────────────────────────────┘ └────────────────────────────────┘ + * + * 2. dml-override.slice sets DefaultMemoryLow=10. As such, dml-override-empty.service should also + * end up with a memory.low of 10. dml-override.slice should still have a memory.low of 50. + * + * ┌───────────┐ + * │ dml.slice │ + * └─────┬─────┘ + * DefaultMemoryLow=10 + * ┌─────────┴──────────┐ + * │ dml-override.slice │ + * └─────────┬──────────┘ + * no new settings + * ┌─────────────┴──────────────┐ + * │ dml-override-empty.service │ + * └────────────────────────────┘ + * + * 3. dml-discard.slice sets DefaultMemoryLow= with no rvalue. As such, + * dml-discard-empty.service should end up with a value of 0. + * dml-discard-explicit-ml.service sets MemoryLow=70, and as such should have that override the + * reset DefaultMemoryLow value. dml-discard.slice should still have an eventual memory.low of 50. + * + * ┌───────────┐ + * │ dml.slice │ + * └─────┬─────┘ + * DefaultMemoryLow= + * ┌─────────┴─────────┐ + * │ dml-discard.slice │ + * └─────────┬─────────┘ + * ┌──────────────┴───────────────┐ + * no new settings MemoryLow=15 + * ┌─────────────┴─────────────┐ ┌─────────────┴──────────────┐ + * │ dml-discard-empty.service │ │ dml-discard-set-ml.service │ + * └───────────────────────────┘ └────────────────────────────┘ + */ + assert_se(manager_load_startable_unit_or_warn(m, "dml.slice", NULL, &dml) >= 0); + + assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough.slice", NULL, &dml_passthrough) >= 0); + assert_se(UNIT_DEREF(dml_passthrough->slice) == dml); + assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-empty.service", NULL, &dml_passthrough_empty) >= 0); + assert_se(UNIT_DEREF(dml_passthrough_empty->slice) == dml_passthrough); + assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-dml.service", NULL, &dml_passthrough_set_dml) >= 0); + assert_se(UNIT_DEREF(dml_passthrough_set_dml->slice) == dml_passthrough); + assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-ml.service", NULL, &dml_passthrough_set_ml) >= 0); + assert_se(UNIT_DEREF(dml_passthrough_set_ml->slice) == dml_passthrough); + + assert_se(manager_load_startable_unit_or_warn(m, "dml-override.slice", NULL, &dml_override) >= 0); + assert_se(UNIT_DEREF(dml_override->slice) == dml); + assert_se(manager_load_startable_unit_or_warn(m, "dml-override-empty.service", NULL, &dml_override_empty) >= 0); + assert_se(UNIT_DEREF(dml_override_empty->slice) == dml_override); + + assert_se(manager_load_startable_unit_or_warn(m, "dml-discard.slice", NULL, &dml_discard) >= 0); + assert_se(UNIT_DEREF(dml_discard->slice) == dml); + assert_se(manager_load_startable_unit_or_warn(m, "dml-discard-empty.service", NULL, &dml_discard_empty) >= 0); + assert_se(UNIT_DEREF(dml_discard_empty->slice) == dml_discard); + assert_se(manager_load_startable_unit_or_warn(m, "dml-discard-set-ml.service", NULL, &dml_discard_set_ml) >= 0); + assert_se(UNIT_DEREF(dml_discard_set_ml->slice) == dml_discard); + + root = UNIT_DEREF(dml->slice); + assert_se(!UNIT_ISSET(root->slice)); + + assert_se(unit_get_ancestor_memory_low(root) == CGROUP_LIMIT_MIN); + + assert_se(unit_get_ancestor_memory_low(dml) == CGROUP_LIMIT_MIN); + dml_tree_default = unit_get_cgroup_context(dml)->default_memory_low; + assert_se(dml_tree_default == 50); + + assert_se(unit_get_ancestor_memory_low(dml_passthrough) == 100); + assert_se(unit_get_ancestor_memory_low(dml_passthrough_empty) == dml_tree_default); + assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_dml) == 50); + assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_ml) == 0); + + assert_se(unit_get_ancestor_memory_low(dml_override) == dml_tree_default); + assert_se(unit_get_ancestor_memory_low(dml_override_empty) == 10); + + assert_se(unit_get_ancestor_memory_low(dml_discard) == dml_tree_default); + assert_se(unit_get_ancestor_memory_low(dml_discard_empty) == CGROUP_LIMIT_MIN); + assert_se(unit_get_ancestor_memory_low(dml_discard_set_ml) == 15); + + return 0; +} + +int main(int argc, char* argv[]) { + int rc = EXIT_SUCCESS; + + test_setup_logging(LOG_DEBUG); + + TEST_REQ_RUNNING_SYSTEMD(rc = test_default_memory_low()); + + return rc; +} diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index a3239d73f5..b54b5e76c6 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -341,7 +341,7 @@ static void test_is_wanted_print(bool header) { log_info("cmdline: %s", cmdline); if (header) { - log_info(_CGROUP_HIEARCHY_); + log_info(_CGROUP_HIERARCHY_); (void) system("findmnt -n /sys/fs/cgroup"); } diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c new file mode 100644 index 0000000000..013b36e2a7 --- /dev/null +++ b/src/test/test-chase-symlinks.c @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#include <getopt.h> + +#include "fd-util.h" +#include "fs-util.h" +#include "log.h" +#include "main-func.h" + +static char *arg_root = NULL; +static int arg_flags = 0; + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_ROOT = 0x1000, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "root", required_argument, NULL, ARG_ROOT }, + + { "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT }, + { "nonexistent", no_argument, NULL, CHASE_NONEXISTENT }, + { "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS }, + { "safe", no_argument, NULL, CHASE_SAFE }, + { "open", no_argument, NULL, CHASE_OPEN }, + { "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH }, + { "step", no_argument, NULL, CHASE_STEP }, + { "nofollow", no_argument, NULL, CHASE_NOFOLLOW }, + { "warn", no_argument, NULL, CHASE_WARN }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) + switch (c) { + + case 'h': + printf("Syntax:\n" + " %s [OPTION...] path...\n" + "Options:\n" + , argv[0]); + for (size_t i = 0; i < ELEMENTSOF(options) - 1; i++) + printf(" --%s\n", options[i].name); + return 0; + + case ARG_ROOT: + arg_root = optarg; + break; + + case CHASE_PREFIX_ROOT: + case CHASE_NONEXISTENT: + case CHASE_NO_AUTOFS: + case CHASE_SAFE: + case CHASE_OPEN: + case CHASE_TRAIL_SLASH: + case CHASE_STEP: + case CHASE_NOFOLLOW: + case CHASE_WARN: + arg_flags |= c; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (optind == argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "At least one argument is required."); + + return 1; +} + +static int run(int argc, char **argv) { + int r; + + log_show_color(true); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + for (int i = optind; i < argc; i++) { + _cleanup_free_ char *p = NULL; + + printf("%s ", argv[i]); + fflush(stdout); + + r = chase_symlinks(argv[i], arg_root, arg_flags, &p); + if (r < 0) + log_error_errno(r, "failed: %m"); + else + log_info("→ %s", p); + + if (FLAGS_SET(arg_flags, CHASE_OPEN)) + safe_close(r); + } + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/test/test-condition.c b/src/test/test-condition.c index 2a5e3aba80..a79263a50b 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -13,6 +13,7 @@ #include "audit-util.h" #include "cgroup-util.h" #include "condition.h" +#include "cpu-set-util.h" #include "efivars.h" #include "hostname-util.h" #include "id128-util.h" @@ -42,77 +43,77 @@ static void test_condition_test_path(void) { condition = condition_new(CONDITION_PATH_EXISTS, "/bin/s?", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, true); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, true); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_DIRECTORY, "/bin", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_DIRECTORY_NOT_EMPTY, "/bin", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_FILE_NOT_EMPTY, "/bin/sh", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/bin/sh", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/etc/passwd", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/proc", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/bin", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_READ_WRITE, "/tmp", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); } @@ -132,12 +133,12 @@ static void test_condition_test_control_group_controller(void) { /* Invalid controllers are ignored */ condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, true); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); assert_se(cg_mask_supported(&system_mask) >= 0); @@ -150,23 +151,23 @@ static void test_condition_test_control_group_controller(void) { log_info("this controller is available"); condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, true); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); } else { log_info("this controller is unavailable"); condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, true); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); } } @@ -176,12 +177,12 @@ static void test_condition_test_control_group_controller(void) { condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, true); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); } @@ -217,17 +218,17 @@ static void test_condition_test_host(void) { condition = condition_new(CONDITION_HOST, sid, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_HOST, sid, false, true); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); hostname = gethostname_malloc(); @@ -239,7 +240,7 @@ static void test_condition_test_host(void) { else { condition = condition_new(CONDITION_HOST, hostname, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); } } @@ -276,12 +277,12 @@ static void test_condition_test_kernel_command_line(void) { condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "thisreallyshouldntbeonthekernelcommandline", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "andthis=neither", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); } @@ -292,24 +293,26 @@ static void test_condition_test_kernel_version(void) { condition = condition_new(CONDITION_KERNEL_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "*", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); + /* An artificially empty condition. It evaluates to true, but normally + * such condition cannot be created, because the condition list is reset instead. */ condition = condition_new(CONDITION_KERNEL_VERSION, "", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); assert_se(uname(&u) >= 0); condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); strshorten(u.release, 4); @@ -317,59 +320,79 @@ static void test_condition_test_kernel_version(void) { condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); /* 0.1.2 would be a very very very old kernel */ condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); + condition_free(condition); + + condition = condition_new(CONDITION_KERNEL_VERSION, ">0.1.2", false, false); + assert_se(condition); + assert_se(condition_test(condition) > 0); + condition_free(condition); + + condition = condition_new(CONDITION_KERNEL_VERSION, "'>0.1.2' '<9.0.0'", false, false); + assert_se(condition); + assert_se(condition_test(condition) > 0); + condition_free(condition); + + condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2 < 9.0.0", false, false); + assert_se(condition); + assert_se(condition_test(condition) == -EINVAL); + condition_free(condition); + + condition = condition_new(CONDITION_KERNEL_VERSION, ">", false, false); + assert_se(condition); + assert_se(condition_test(condition) == -EINVAL); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, ">= 0.1.2", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "< 0.1.2", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "<= 0.1.2", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "= 0.1.2", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); /* 4711.8.15 is a very very very future kernel */ condition = condition_new(CONDITION_KERNEL_VERSION, "< 4711.8.15", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "<= 4711.8.15", false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "= 4711.8.15", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, "> 4711.8.15", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_KERNEL_VERSION, ">= 4711.8.15", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); assert_se(uname(&u) >= 0); @@ -377,31 +400,31 @@ static void test_condition_test_kernel_version(void) { v = strjoina(">=", u.release); condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); v = strjoina("= ", u.release); condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); v = strjoina("<=", u.release); condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); v = strjoina("> ", u.release); condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); v = strjoina("< ", u.release); condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); } @@ -410,12 +433,12 @@ static void test_condition_test_null(void) { condition = condition_new(CONDITION_NULL, NULL, false, false); assert_se(condition); - assert_se(condition_test(condition)); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_NULL, NULL, false, true); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); } @@ -424,7 +447,7 @@ static void test_condition_test_security(void) { condition = condition_new(CONDITION_SECURITY, "garbage oifdsjfoidsjoj", false, false); assert_se(condition); - assert_se(!condition_test(condition)); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "selinux", false, true); diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c index 9fd8b6b590..61811311f4 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -30,7 +30,7 @@ static void setup_test_dir(char *tmp_dir, const char *files, ...) { while (files) { _cleanup_free_ char *path; - assert_se(path = strappend(tmp_dir, files)); + assert_se(path = path_join(tmp_dir, files)); (void) mkdir_parents(path, 0755); assert_se(write_string_file(path, "foobar", WRITE_STRING_FILE_CREATE) >= 0); @@ -102,11 +102,11 @@ static void test_conf_files_insert(const char *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"); + *foo1 = path_join(root, "/dir1/foo.conf"), + *foo2 = path_join(root, "/dir2/foo.conf"), + *bar2 = path_join(root, "/dir2/bar.conf"), + *zzz3 = path_join(root, "/dir3/zzz.conf"), + *whatever = path_join(root, "/whatever.conf"); assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); assert_se(strv_equal(s, STRV_MAKE(foo2))); diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 1738938fce..597265efa6 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -231,6 +231,13 @@ static const char* const config_file[] = { "setting1=1\n", /* repeated settings */ "[Section]\n" + "[Section]\n" + "setting1=1\n" + "setting1=2\\\n" + " \n" /* empty line breaks continuation */ + "setting1=1\n", /* repeated settings */ + + "[Section]\n" "setting1=1\\\n" /* normal continuation */ "2\\\n" "3\n", @@ -330,32 +337,32 @@ static void test_config_parse(unsigned i, const char *s) { CONFIG_PARSE_WARN, NULL); switch (i) { - case 0 ... 3: + case 0 ... 4: assert_se(r == 0); assert_se(streq(setting1, "1")); break; - case 4 ... 9: + case 5 ... 10: assert_se(r == 0); assert_se(streq(setting1, "1 2 3")); break; - case 10: + case 11: assert_se(r == 0); assert_se(streq(setting1, "1\\\\ \\\\2")); break; - case 11: + case 12: assert_se(r == 0); assert_se(streq(setting1, x1000("ABCD"))); break; - case 12 ... 13: + case 13 ... 14: assert_se(r == 0); assert_se(streq(setting1, x1000("ABCD") " foobar")); break; - case 14 ... 15: + case 15 ... 16: assert_se(r == -ENOBUFS); assert_se(setting1 == NULL); break; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 5f4bc39580..5f7b9e5ce8 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -52,8 +52,8 @@ static void test_copy_file_fd(void) { char in_fn[] = "/tmp/test-copy-file-fd-XXXXXX"; char out_fn[] = "/tmp/test-copy-file-fd-XXXXXX"; _cleanup_close_ int in_fd = -1, out_fd = -1; - char text[] = "boohoo\nfoo\n\tbar\n"; - char buf[64] = {0}; + const char *text = "boohoo\nfoo\n\tbar\n"; + char buf[64] = {}; log_info("%s", __func__); @@ -67,7 +67,7 @@ static void test_copy_file_fd(void) { assert_se(copy_file_fd(in_fn, out_fd, COPY_REFLINK) >= 0); assert_se(lseek(out_fd, SEEK_SET, 0) == 0); - assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1); + assert_se(read(out_fd, buf, sizeof buf) == (ssize_t) strlen(text)); assert_se(streq(buf, text)); unlink(in_fn); @@ -92,7 +92,7 @@ static void test_copy_tree(void) { STRV_FOREACH(p, files) { _cleanup_free_ char *f; - assert_se(f = strappend(original_dir, *p)); + assert_se(f = path_join(original_dir, *p)); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0); @@ -101,8 +101,8 @@ static void test_copy_tree(void) { STRV_FOREACH_PAIR(link, p, links) { _cleanup_free_ char *f, *l; - assert_se(f = strappend(original_dir, *p)); - assert_se(l = strappend(original_dir, *link)); + assert_se(f = path_join(original_dir, *p)); + assert_se(l = path_join(original_dir, *link)); assert_se(mkdir_parents(l, 0755) >= 0); assert_se(symlink(f, l) == 0); @@ -117,7 +117,7 @@ static void test_copy_tree(void) { _cleanup_free_ char *buf, *f; size_t sz; - assert_se(f = strappend(copy_dir, *p)); + assert_se(f = path_join(copy_dir, *p)); assert_se(access(f, F_OK) == 0); assert_se(read_full_file(f, &buf, &sz) == 0); diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c index c9272459b4..e1dd2eb32b 100644 --- a/src/test/test-cpu-set-util.c +++ b/src/test/test-cpu-set-util.c @@ -2,125 +2,289 @@ #include "alloc-util.h" #include "cpu-set-util.h" +#include "string-util.h" #include "macro.h" static void test_parse_cpu_set(void) { - cpu_set_t *c = NULL; - int ncpus; + CPUSet c = {}; + _cleanup_free_ char *str = NULL; int cpu; + log_info("/* %s */", __func__); + + /* Single value */ + assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_ISSET_S(0, c.allocated, c.set)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 1); + + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "0")); + str = mfree(str); + cpu_set_reset(&c); + /* Simple range (from CPUAffinity example) */ - ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); - c = cpu_set_mfree(c); + assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.set); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_ISSET_S(1, c.allocated, c.set)); + assert_se(CPU_ISSET_S(2, c.allocated, c.set)); + assert_se(CPU_ISSET_S(4, c.allocated, c.set)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); + + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "1-2 4")); + str = mfree(str); + cpu_set_reset(&c); /* A more interesting range */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "0-3 8-11")); + str = mfree(str); + cpu_set_reset(&c); /* Quoted strings */ - ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); + assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 4); for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "8-11")); + str = mfree(str); + cpu_set_reset(&c); /* Use commas as separators */ - ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + cpu_set_reset(&c); /* Commas with spaces (and trailing comma, space) */ - ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 9); for (cpu = 0; cpu < 8; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + + assert_se(CPU_ISSET_S(63, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "0-7 63")); + str = mfree(str); + cpu_set_reset(&c); /* Ranges */ - ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + cpu_set_reset(&c); /* Ranges with trailing comma, space */ - ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 8); for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "0-3 8-11")); + str = mfree(str); + cpu_set_reset(&c); /* Negative range (returns empty cpu_set) */ - ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); - c = cpu_set_mfree(c); + assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 0); + cpu_set_reset(&c); /* Overlapping ranges */ - ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 12); for (cpu = 0; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "0-11")); + str = mfree(str); + cpu_set_reset(&c); /* Mix ranges and individual CPUs */ - ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); - assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0); + assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8)); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 10); + assert_se(CPU_ISSET_S(0, c.allocated, c.set)); + assert_se(CPU_ISSET_S(2, c.allocated, c.set)); for (cpu = 4; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = cpu_set_mfree(c); + assert_se(CPU_ISSET_S(cpu, c.allocated, c.set)); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "0 2 4-11")); + str = mfree(str); + cpu_set_reset(&c); /* Garbage */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); + assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); + assert_se(!c.set); + assert_se(c.allocated == 0); /* Range with garbage */ - ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); + assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); + assert_se(!c.set); + assert_se(c.allocated == 0); /* Empty string */ - c = NULL; - ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus == 0); /* empty string returns 0 */ - assert_se(!c); + assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); + assert_se(!c.set); /* empty string returns NULL */ + assert_se(c.allocated == 0); /* Runaway quoted string */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); + assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL); + assert_se(!c.set); + assert_se(c.allocated == 0); + + /* Maximum allocation */ + assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 192); + assert_se(str = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", str); + str = mfree(str); + assert_se(str = cpu_set_to_range_string(&c)); + log_info("cpu_set_to_range_string: %s", str); + assert_se(streq(str, "8000-8191")); + str = mfree(str); + cpu_set_reset(&c); +} + +static void test_parse_cpu_set_extend(void) { + CPUSet c = {}; + _cleanup_free_ char *s1 = NULL, *s2 = NULL; + + log_info("/* %s */", __func__); + + assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 2); + assert_se(s1 = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", s1); + + assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); + assert_se(s2 = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", s2); + + assert_se(parse_cpu_set_extend("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); + assert_se(!c.set); + assert_se(c.allocated == 0); + log_info("cpu_set_to_string: (null)"); +} + +static void test_cpu_set_to_from_dbus(void) { + _cleanup_(cpu_set_reset) CPUSet c = {}, c2 = {}; + _cleanup_free_ char *s = NULL; + + log_info("/* %s */", __func__); + + assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); + assert_se(s = cpu_set_to_string(&c)); + log_info("cpu_set_to_string: %s", s); + assert_se(CPU_COUNT_S(c.allocated, c.set) == 104); + + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + static const char expected[32] = + "\x0A\x01\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\xF0\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\x01"; + + assert_se(cpu_set_to_dbus(&c, &array, &allocated) == 0); + assert_se(array); + assert_se(allocated == c.allocated); + + assert_se(allocated <= sizeof expected); + assert_se(allocated >= DIV_ROUND_UP(201u, 8u)); /* We need at least 201 bits for our mask */ + assert(memcmp(array, expected, allocated) == 0); + + assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0); + assert_se(c2.set); + assert_se(c2.allocated == c.allocated); + assert_se(memcmp(c.set, c2.set, c.allocated) == 0); +} + +static void test_cpus_in_affinity_mask(void) { + int r; + + r = cpus_in_affinity_mask(); + assert(r > 0); + log_info("cpus_in_affinity_mask: %d", r); } int main(int argc, char *argv[]) { + log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1)); + log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9)); + log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64)); + log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65)); + log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024)); + log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025)); + log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191)); + test_parse_cpu_set(); + test_parse_cpu_set_extend(); + test_cpus_in_affinity_mask(); + test_cpu_set_to_from_dbus(); return 0; } diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 701594fe53..633cc42534 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -7,14 +7,17 @@ #include "bus-util.h" #include "manager.h" #include "rm-rf.h" +#include "strv.h" #include "test-helper.h" #include "tests.h" +#include "service.h" int main(int argc, char *argv[]) { _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; _cleanup_(manager_freep) Manager *m = NULL; - Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL, *unit_with_multiple_dashes = NULL; + Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, + *h = NULL, *i = NULL, *a_conj = NULL, *unit_with_multiple_dashes = NULL; Job *j; int r; @@ -94,6 +97,30 @@ int main(int argc, char *argv[]) { assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); + printf("Load5:\n"); + manager_clear_jobs(m); + assert_se(manager_load_startable_unit_or_warn(m, "i.service", NULL, &i) >= 0); + SERVICE(a)->state = SERVICE_RUNNING; + SERVICE(d)->state = SERVICE_RUNNING; + manager_dump_units(m, stdout, "\t"); + + printf("Test11: (Start/stop job ordering, execution cycle)\n"); + assert_se(manager_add_job(m, JOB_START, i, JOB_FAIL, NULL, NULL, &j) == 0); + assert_se(a->job && a->job->type == JOB_STOP); + assert_se(d->job && d->job->type == JOB_STOP); + assert_se(b->job && b->job->type == JOB_START); + manager_dump_jobs(m, stdout, "\t"); + + printf("Load6:\n"); + manager_clear_jobs(m); + assert_se(manager_load_startable_unit_or_warn(m, "a-conj.service", NULL, &a_conj) >= 0); + SERVICE(a)->state = SERVICE_DEAD; + manager_dump_units(m, stdout, "\t"); + + printf("Test12: (Trivial cycle, Unfixable)\n"); + assert_se(manager_add_job(m, JOB_START, a_conj, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK); + manager_dump_jobs(m, stdout, "\t"); + assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b)); assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c)); diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c new file mode 100644 index 0000000000..47f86a5676 --- /dev/null +++ b/src/test/test-env-file.c @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "env-file.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "strv.h" +#include "tests.h" +#include "tmpfile-util.h" + +#define env_file_1 \ + "a=a\n" \ + "b=b\\\n" \ + "c\n" \ + "d=d\\\n" \ + "e\\\n" \ + "f\n" \ + "g=g\\ \n" \ + "h=h\n" \ + "i=i\\" + +#define env_file_2 \ + "a=a\\\n" + +#define env_file_3 \ + "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \ + "#--nouser-config \\\n" \ + "normal=line" + +#define env_file_4 \ + "# Generated\n" \ + "\n" \ + "HWMON_MODULES=\"coretemp f71882fg\"\n" \ + "\n" \ + "# For compatibility reasons\n" \ + "\n" \ + "MODULE_0=coretemp\n" \ + "MODULE_1=f71882fg" + +#define env_file_5 \ + "a=\n" \ + "b=" + +static void test_load_env_file_1(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1)); + + r = load_env_file(NULL, name, &data); + assert_se(r == 0); + assert_se(streq(data[0], "a=a")); + assert_se(streq(data[1], "b=bc")); + assert_se(streq(data[2], "d=def")); + assert_se(streq(data[3], "g=g ")); + assert_se(streq(data[4], "h=h")); + assert_se(streq(data[5], "i=i")); + assert_se(data[6] == NULL); +} + +static void test_load_env_file_2(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2)); + + r = load_env_file(NULL, name, &data); + assert_se(r == 0); + assert_se(streq(data[0], "a=a")); + assert_se(data[1] == NULL); +} + +static void test_load_env_file_3(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3)); + + r = load_env_file(NULL, name, &data); + assert_se(r == 0); + assert_se(data == NULL); +} + +static void test_load_env_file_4(void) { + _cleanup_strv_free_ char **data = NULL; + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + int r; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4)); + + r = load_env_file(NULL, name, &data); + assert_se(r == 0); + assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); + assert_se(streq(data[1], "MODULE_0=coretemp")); + assert_se(streq(data[2], "MODULE_1=f71882fg")); + assert_se(data[3] == NULL); +} + +static void test_load_env_file_5(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5)); + + r = load_env_file(NULL, name, &data); + assert_se(r == 0); + assert_se(streq(data[0], "a=")); + assert_se(streq(data[1], "b=")); + assert_se(data[2] == NULL); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + test_load_env_file_1(); + test_load_env_file_2(); + test_load_env_file_3(); + test_load_env_file_4(); + test_load_env_file_5(); +} diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index f57a26021c..17dacda70f 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -122,10 +122,10 @@ static void test_env_strv_get_n(void) { assert_se(!strv_env_get_n(env, "PATH__", 4, 0)); assert_se(!strv_env_get_n(env, "PATH", 4, 0)); - assert_se(streq(strv_env_get_n(env, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT), - getenv("PATH"))); - assert_se(streq(strv_env_get_n(env, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT), - getenv("PATH"))); + assert_se(streq_ptr(strv_env_get_n(env, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT), + getenv("PATH"))); + assert_se(streq_ptr(strv_env_get_n(env, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT), + getenv("PATH"))); } static void test_replace_env(bool braceless) { diff --git a/src/test/test-escape.c b/src/test/test-escape.c index 4ee4aa974d..add17f9547 100644 --- a/src/test/test-escape.c +++ b/src/test/test-escape.c @@ -6,10 +6,45 @@ #include "tests.h" static void test_cescape(void) { - _cleanup_free_ char *escaped; + _cleanup_free_ char *t; - assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); - assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); + assert_se(t = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); + assert_se(streq(t, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); +} + +static void test_xescape(void) { + _cleanup_free_ char *t; + + assert_se(t = xescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", "")); + assert_se(streq(t, "abc\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb")); +} + +static void test_xescape_full(bool eight_bits) { + const char* escaped = !eight_bits ? + "a\\x62c\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb" : + "a\\x62c\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\177\234\313"; + const unsigned full_fit = !eight_bits ? 55 : 46; + + for (unsigned i = 0; i < 60; i++) { + _cleanup_free_ char *t; + + assert_se(t = xescape_full("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", "b", i, eight_bits)); + + log_info("%02d: %s", i, t); + + if (i >= full_fit) + assert_se(streq(t, escaped)); + else if (i >= 3) { + /* We need up to four columns, so up to three three columns may be wasted */ + assert_se(strlen(t) == i || strlen(t) == i - 1 || strlen(t) == i - 2 || strlen(t) == i - 3); + assert_se(strneq(t, escaped, i - 3) || strneq(t, escaped, i - 4) || + strneq(t, escaped, i - 5) || strneq(t, escaped, i - 6)); + assert_se(endswith(t, "...")); + } else { + assert_se(strlen(t) == i); + assert_se(strneq(t, "...", i)); + } + } } static void test_cunescape(void) { @@ -123,6 +158,9 @@ int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); test_cescape(); + test_xescape(); + test_xescape_full(false); + test_xescape_full(true); test_cunescape(); test_shell_escape(); test_shell_maybe_quote(); diff --git a/src/test/test-exec-util.c b/src/test/test-exec-util.c index 25ca7a2bc9..ec51891634 100644 --- a/src/test/test-exec-util.c +++ b/src/test/test-exec-util.c @@ -324,7 +324,7 @@ static void test_environment_gathering(void) { assert_se(chmod(name3, 0755) == 0); /* When booting in containers or without initramfs there might not be - * any PATH in the environ and if there is no PATH /bin/sh built-in + * any PATH in the environment and if there is no PATH /bin/sh built-in * PATH may leak and override systemd's DEFAULT_PATH which is not * good. Force our own PATH in environment, to prevent expansion of sh * built-in $PATH */ @@ -361,7 +361,10 @@ static void test_environment_gathering(void) { assert_se(streq(strv_env_get(env, "PATH"), DEFAULT_PATH ":/no/such/file")); /* reset environ PATH */ - (void) setenv("PATH", old, 1); + if (old) + (void) setenv("PATH", old, 1); + else + (void) unsetenv("PATH"); } static void test_error_catching(void) { @@ -399,6 +402,50 @@ static void test_error_catching(void) { assert_se(r == 42); } +static void test_exec_command_flags_from_strv(void) { + ExecCommandFlags flags = 0; + char **valid_strv = STRV_MAKE("no-env-expand", "no-setuid", "ignore-failure"); + char **invalid_strv = STRV_MAKE("no-env-expand", "no-setuid", "nonexistent-option", "ignore-failure"); + int r; + + r = exec_command_flags_from_strv(valid_strv, &flags); + + assert_se(r == 0); + assert_se(FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND)); + assert_se(FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)); + assert_se(FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE)); + assert_se(!FLAGS_SET(flags, EXEC_COMMAND_AMBIENT_MAGIC)); + assert_se(!FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED)); + + r = exec_command_flags_from_strv(invalid_strv, &flags); + + assert_se(r == -EINVAL); +} + +static void test_exec_command_flags_to_strv(void) { + _cleanup_strv_free_ char **opts = NULL, **empty_opts = NULL, **invalid_opts = NULL; + ExecCommandFlags flags = 0; + int r; + + flags |= (EXEC_COMMAND_AMBIENT_MAGIC|EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_IGNORE_FAILURE); + + r = exec_command_flags_to_strv(flags, &opts); + + assert_se(r == 0); + assert_se(strv_equal(opts, STRV_MAKE("ignore-failure", "ambient", "no-env-expand"))); + + r = exec_command_flags_to_strv(0, &empty_opts); + + assert_se(r == 0); + assert_se(strv_equal(empty_opts, STRV_MAKE_EMPTY)); + + flags = _EXEC_COMMAND_FLAGS_INVALID; + + r = exec_command_flags_to_strv(flags, &invalid_opts); + + assert_se(r == -EINVAL); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -408,6 +455,8 @@ int main(int argc, char *argv[]) { test_stdout_gathering(); test_environment_gathering(); test_error_catching(); + test_exec_command_flags_from_strv(); + test_exec_command_flags_to_strv(); return 0; } diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 9f1cb0ca38..435ab39cd2 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -33,7 +33,13 @@ static bool can_unshare; typedef void (*test_function_t)(Manager *m); -static void check(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) { +static int cld_dumped_to_killed(int code) { + /* Depending on the system, seccomp version, … some signals might result in dumping, others in plain + * killing. Let's ignore the difference here, and map both cases to CLD_KILLED */ + return code == CLD_DUMPED ? CLD_KILLED : code; +} + +static void wait_for_service_finish(Manager *m, Unit *unit) { Service *service = NULL; usec_t ts; usec_t timeout = 2 * USEC_PER_MINUTE; @@ -61,17 +67,49 @@ static void check(const char *func, Manager *m, Unit *unit, int status_expected, exit(EXIT_FAILURE); } } +} + +static void check_main_result(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) { + Service *service = NULL; + + assert_se(m); + assert_se(unit); + + wait_for_service_finish(m, unit); + + service = SERVICE(unit); exec_status_dump(&service->main_exec_status, stdout, "\t"); + + if (cld_dumped_to_killed(service->main_exec_status.code) != cld_dumped_to_killed(code_expected)) { + log_error("%s: %s: exit code %d, expected %d", + func, unit->id, + service->main_exec_status.code, code_expected); + abort(); + } + if (service->main_exec_status.status != status_expected) { log_error("%s: %s: exit status %d, expected %d", func, unit->id, service->main_exec_status.status, status_expected); abort(); } - if (service->main_exec_status.code != code_expected) { - log_error("%s: %s: exit code %d, expected %d", +} + +static void check_service_result(const char *func, Manager *m, Unit *unit, ServiceResult result_expected) { + Service *service = NULL; + + assert_se(m); + assert_se(unit); + + wait_for_service_finish(m, unit); + + service = SERVICE(unit); + + if (service->result != result_expected) { + log_error("%s: %s: service end result %s, expected %s", func, unit->id, - service->main_exec_status.code, code_expected); + service_result_to_string(service->result), + service_result_to_string(result_expected)); abort(); } } @@ -165,7 +203,17 @@ static void test(const char *func, Manager *m, const char *unit_name, int status assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0); assert_se(unit_start(unit) >= 0); - check(func, m, unit, status_expected, code_expected); + check_main_result(func, m, unit, status_expected, code_expected); +} + +static void test_service(const char *func, Manager *m, const char *unit_name, ServiceResult result_expected) { + Unit *unit; + + assert_se(unit_name); + + assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0); + assert_se(unit_start(unit) >= 0); + check_service_result(func, m, unit, result_expected); } static void test_exec_bindpaths(Manager *m) { @@ -179,13 +227,12 @@ static void test_exec_bindpaths(Manager *m) { } static void test_exec_cpuaffinity(Manager *m) { - _cleanup_cpu_free_ cpu_set_t *c = NULL; - unsigned n; + _cleanup_(cpu_set_reset) CPUSet c = {}; - assert_se(c = cpu_set_malloc(&n)); - assert_se(sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0); + assert_se(cpu_set_realloc(&c, 8192) >= 0); /* just allocate the maximum possible size */ + assert_se(sched_getaffinity(0, c.allocated, c.set) >= 0); - if (CPU_ISSET_S(0, CPU_ALLOC_SIZE(n), c) == 0) { + if (!CPU_ISSET_S(0, c.allocated, c.set)) { log_notice("Cannot use CPU 0, skipping %s", __func__); return; } @@ -193,8 +240,8 @@ static void test_exec_cpuaffinity(Manager *m) { test(__func__, m, "exec-cpuaffinity1.service", 0, CLD_EXITED); test(__func__, m, "exec-cpuaffinity2.service", 0, CLD_EXITED); - if (CPU_ISSET_S(1, CPU_ALLOC_SIZE(n), c) == 0 || - CPU_ISSET_S(2, CPU_ALLOC_SIZE(n), c) == 0) { + if (!CPU_ISSET_S(1, c.allocated, c.set) || + !CPU_ISSET_S(2, c.allocated, c.set)) { log_notice("Cannot use CPU 1 or 2, skipping remaining tests in %s", __func__); return; } @@ -424,7 +471,12 @@ static void test_exec_restrictnamespaces(Manager *m) { } static void test_exec_systemcallfilter_system(Manager *m) { -#if HAVE_SECCOMP +/* Skip this particular test case when running under ASan, as + * LSan intermittently segfaults when accessing memory right + * after the test finishes. Generally, ASan & LSan don't like + * the seccomp stuff. + */ +#if HAVE_SECCOMP && !HAS_FEATURE_ADDRESS_SANITIZER if (!is_seccomp_available()) { log_notice("Seccomp not available, skipping %s", __func__); return; @@ -711,6 +763,11 @@ static void test_exec_standardoutput_append(Manager *m) { test(__func__, m, "exec-standardoutput-append.service", 0, CLD_EXITED); } +static void test_exec_condition(Manager *m) { + test_service(__func__, m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE); + test_service(__func__, m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION); +} + typedef struct test_entry { test_function_t f; const char *name; @@ -740,7 +797,6 @@ static int run_tests(UnitFileScope scope, const test_entry tests[], char **patte return 0; } - int main(int argc, char *argv[]) { _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; _cleanup_free_ char *test_execute_path = NULL; @@ -750,6 +806,7 @@ int main(int argc, char *argv[]) { entry(test_exec_ambientcapabilities), entry(test_exec_bindpaths), entry(test_exec_capabilityboundingset), + entry(test_exec_condition), entry(test_exec_cpuaffinity), entry(test_exec_environment), entry(test_exec_environmentfile), diff --git a/src/test/test-exit-status.c b/src/test/test-exit-status.c new file mode 100644 index 0000000000..a007bda5c4 --- /dev/null +++ b/src/test/test-exit-status.c @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "exit-status.h" +#include "string-util.h" +#include "tests.h" + +static void test_exit_status_to_string(void) { + log_info("/* %s */", __func__); + + for (int i = -1; i <= 256; i++) { + const char *s, *class; + + s = exit_status_to_string(i, EXIT_STATUS_FULL); + class = exit_status_class(i); + log_info("%d: %s%s%s%s", + i, s ?: "-", + class ? " (" : "", class ?: "", class ? ")" : ""); + + if (s) + assert_se(exit_status_from_string(s) == i); + } +} + +static void test_exit_status_from_string(void) { + log_info("/* %s */", __func__); + + assert_se(exit_status_from_string("11") == 11); + assert_se(exit_status_from_string("-1") == -ERANGE); + assert_se(exit_status_from_string("256") == -ERANGE); + assert_se(exit_status_from_string("foo") == -EINVAL); + assert_se(exit_status_from_string("SUCCESS") == 0); + assert_se(exit_status_from_string("FAILURE") == 1); +} + +static void test_exit_status_NUMA_POLICY(void) { + log_info("/* %s */", __func__); + + assert_se(streq(exit_status_to_string(EXIT_NUMA_POLICY, EXIT_STATUS_FULL), "NUMA_POLICY")); + assert_se(streq(exit_status_to_string(EXIT_NUMA_POLICY, EXIT_STATUS_SYSTEMD), "NUMA_POLICY")); + assert_se(!exit_status_to_string(EXIT_NUMA_POLICY, EXIT_STATUS_BSD)); + assert_se(!exit_status_to_string(EXIT_NUMA_POLICY, EXIT_STATUS_LSB)); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + test_exit_status_to_string(); + test_exit_status_from_string(); + test_exit_status_NUMA_POLICY(); + + return 0; +} diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c index 30019382ae..bf47a598a9 100644 --- a/src/test/test-extract-word.c +++ b/src/test/test-extract-word.c @@ -43,12 +43,12 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 9); - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) > 0); assert_se(streq(t, "waldo")); free(t); assert_se(isempty(p)); @@ -64,7 +64,7 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\""; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) == -EINVAL); assert_se(p == original + 1); p = original = "\'"; @@ -74,7 +74,7 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\'"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) == -EINVAL); assert_se(p == original + 1); p = original = "\'fooo"; @@ -83,18 +83,42 @@ static void test_extract_first_word(void) { free(t); assert_se(isempty(p)); + p = original = "KEY=val \"KEY2=val with space\" \"KEY3=val with \\\"quotation\\\"\""; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) == 1); + assert_se(streq(t, "KEY=val")); + free(t); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) == 1); + assert_se(streq(t, "KEY2=val with space")); + free(t); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) == 1); + assert_se(streq(t, "KEY3=val with \"quotation\"")); + free(t); + assert_se(isempty(p)); + + p = original = "KEY=val \"KEY2=val space\" \"KEY3=val with \\\"quotation\\\"\""; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) == 1); + assert_se(streq(t, "KEY=val")); + free(t); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) == 1); + assert_se(streq(t, "\"KEY2=val")); + free(t); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) == 1); + assert_se(streq(t, "space\"")); + free(t); + assert_se(startswith(p, "\"KEY3=")); + p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) == -EINVAL); assert_se(p == original + 5); p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo")); free(t); assert_se(isempty(p)); p = original = "\"fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo")); free(t); assert_se(isempty(p)); @@ -106,7 +130,7 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "yay\'foo\'bar"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) > 0); assert_se(streq(t, "yayfoobar")); free(t); assert_se(isempty(p)); @@ -135,7 +159,7 @@ static void test_extract_first_word(void) { free(t); assert_se(p == original + 13); - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE) > 0); assert_se(streq(t, "pi\360\237\222\251le")); free(t); assert_se(isempty(p)); @@ -169,7 +193,7 @@ static void test_extract_first_word(void) { assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo")); free(t); assert_se(isempty(p)); @@ -205,17 +229,17 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo\\")); free(t); assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo\\")); free(t); assert_se(isempty(p)); @@ -265,12 +289,12 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "-N ''"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) > 0); assert_se(streq(t, "-N")); free(t); assert_se(p == original + 3); - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE) > 0); assert_se(streq(t, "")); free(t); assert_se(isempty(p)); @@ -340,12 +364,12 @@ static void test_extract_first_word_and_warn(void) { assert_se(isempty(p)); p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 9); - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "waldo")); free(t); assert_se(isempty(p)); @@ -355,19 +379,19 @@ static void test_extract_first_word_and_warn(void) { assert_se(isempty(p)); p = original = "\""; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 1); p = original = "\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 1); p = original = "\'fooo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 5); p = original = "\'fooo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo")); free(t); assert_se(isempty(p)); @@ -390,7 +414,7 @@ static void test_extract_first_word_and_warn(void) { free(t); assert_se(p == original + 13); - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "pi\360\237\222\251le")); free(t); assert_se(isempty(p)); @@ -414,21 +438,21 @@ static void test_extract_first_word_and_warn(void) { assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foo")); free(t); assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foo")); free(t); assert_se(isempty(p)); @@ -488,7 +512,7 @@ static void test_extract_many_words(void) { free(b); p = original = "'foobar' wa\"ld\"i "; - assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); + assert_se(extract_many_words(&p, NULL, EXTRACT_UNQUOTE, &a, &b, &c, NULL) == 2); assert_se(isempty(p)); assert_se(streq_ptr(a, "foobar")); assert_se(streq_ptr(b, "waldi")); diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 2ff5b9a69d..56af5a8bc3 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -427,7 +427,7 @@ static void test_write_string_file(void) { static void test_write_string_file_no_create(void) { _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX"; _cleanup_close_ int fd; - char buf[64] = {0}; + char buf[64] = {}; fd = mkostemp_safe(fn); assert_se(fd >= 0); @@ -435,7 +435,7 @@ static void test_write_string_file_no_create(void) { assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0); assert_se(write_string_file(fn, "boohoo", 0) == 0); - assert_se(read(fd, buf, sizeof(buf)) == STRLEN("boohoo\n")); + assert_se(read(fd, buf, sizeof buf) == (ssize_t) strlen("boohoo\n")); assert_se(streq(buf, "boohoo\n")); } @@ -629,7 +629,6 @@ static void test_tempfn(void) { static const char chars[] = "Aąę„”\n루\377"; - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" @@ -637,7 +636,7 @@ static void test_fgetc(void) { _cleanup_fclose_ FILE *f = NULL; char c; - f = fmemopen((void*) chars, sizeof(chars), "re"); + f = fmemopen_unlocked((void*) chars, sizeof(chars), "re"); assert_se(f); for (unsigned i = 0; i < sizeof(chars); i++) { @@ -717,7 +716,7 @@ static void test_read_line_one_file(FILE *f) { line = mfree(line); /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first - * character after the previous limit. Let's make use of tha to continue our test. */ + * character after the previous limit. Let's make use of that to continue our test. */ assert_se(read_line(f, 1024, &line) == 62 && streq(line, "line that is supposed to be truncated, because it is so long")); line = mfree(line); @@ -727,7 +726,7 @@ static void test_read_line_one_file(FILE *f) { static void test_read_line(void) { _cleanup_fclose_ FILE *f = NULL; - f = fmemopen((void*) buffer, sizeof(buffer), "re"); + f = fmemopen_unlocked((void*) buffer, sizeof(buffer), "re"); assert_se(f); test_read_line_one_file(f); @@ -792,7 +791,7 @@ static void test_read_line4(void) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *s = NULL; - assert_se(f = fmemopen((void*) eof_endings[i].string, eof_endings[i].length, "r")); + assert_se(f = fmemopen_unlocked((void*) eof_endings[i].string, eof_endings[i].length, "r")); r = read_line(f, (size_t) -1, &s); assert_se((size_t) r == eof_endings[i].length); @@ -813,7 +812,7 @@ static void test_read_nul_string(void) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *s = NULL; - assert_se(f = fmemopen((void*) test, sizeof(test)-1, "r")); + assert_se(f = fmemopen_unlocked((void*) test, sizeof(test)-1, "r")); assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 13 && streq_ptr(s, "string nr. 1")); s = mfree(s); diff --git a/src/test/test-format-table.c b/src/test/test-format-table.c index 5bede5c75b..def9cbda2f 100644 --- a/src/test/test-format-table.c +++ b/src/test/test-format-table.c @@ -34,6 +34,7 @@ int main(int argc, char *argv[]) { _cleanup_(table_unrefp) Table *t = NULL; _cleanup_free_ char *formatted = NULL; + assert_se(setenv("SYSTEMD_COLORS", "0", 1) >= 0); assert_se(setenv("COLUMNS", "40", 1) >= 0); assert_se(t = table_new("one", "two", "three")); @@ -48,6 +49,7 @@ int main(int argc, char *argv[]) { assert_se(table_add_many(t, TABLE_STRING, "a long field", TABLE_STRING, "yyy", + TABLE_SET_UPPERCASE, 1, TABLE_BOOLEAN, false) >= 0); assert_se(table_format(t, &formatted) >= 0); @@ -56,7 +58,7 @@ int main(int argc, char *argv[]) { assert_se(streq(formatted, "ONE TWO THREE\n" "xxx yyy yes\n" - "a long field yyy no\n")); + "a long field YYY no\n")); formatted = mfree(formatted); @@ -68,7 +70,7 @@ int main(int argc, char *argv[]) { assert_se(streq(formatted, "ONE TWO THREE\n" "xxx yyy yes\n" - "a long field yyy no\n")); + "a long field YYY no\n")); formatted = mfree(formatted); @@ -79,7 +81,7 @@ int main(int argc, char *argv[]) { assert_se(streq(formatted, "ONE TWO THR…\n" "xxx yyy yes\n" - "a … yyy no\n")); + "a … YYY no\n")); formatted = mfree(formatted); @@ -113,7 +115,7 @@ int main(int argc, char *argv[]) { assert_se(streq(formatted, "ONE TWO THREE\n" - "a long field yyy no\n" + "a long field YYY no\n" "xxx yyy yes\n")); formatted = mfree(formatted); @@ -139,7 +141,7 @@ int main(int argc, char *argv[]) { printf("%s\n", formatted); assert_se(streq(formatted, - "a long field yyy no\n" + "a long field YYY no\n" "fäää zzz no\n" "fäää uuu yes\n" "xxx yyy yes\n" diff --git a/src/test/test-format-util.c b/src/test/test-format-util.c new file mode 100644 index 0000000000..6558ee2b0a --- /dev/null +++ b/src/test/test-format-util.c @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "format-util.h" +#include "macro.h" +#include "string-util.h" + +static void test_format_bytes_one(uint64_t val, bool trailing_B, const char *iec_with_p, const char *iec_without_p, + const char *si_with_p, const char *si_without_p) { + char buf[FORMAT_BYTES_MAX]; + + assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | (trailing_B ? FORMAT_BYTES_TRAILING_B : 0)), iec_with_p)); + assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, FORMAT_BYTES_USE_IEC | (trailing_B ? FORMAT_BYTES_TRAILING_B : 0)), iec_without_p)); + assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, FORMAT_BYTES_BELOW_POINT | (trailing_B ? FORMAT_BYTES_TRAILING_B : 0)), si_with_p)); + assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, trailing_B ? FORMAT_BYTES_TRAILING_B : 0), si_without_p)); +} + +static void test_format_bytes(void) { + test_format_bytes_one(900, true, "900B", "900B", "900B", "900B"); + test_format_bytes_one(900, false, "900", "900", "900", "900"); + test_format_bytes_one(1023, true, "1023B", "1023B", "1.0K", "1K"); + test_format_bytes_one(1023, false, "1023", "1023", "1.0K", "1K"); + test_format_bytes_one(1024, true, "1.0K", "1K", "1.0K", "1K"); + test_format_bytes_one(1024, false, "1.0K", "1K", "1.0K", "1K"); + test_format_bytes_one(1100, true, "1.0K", "1K", "1.1K", "1K"); + test_format_bytes_one(1500, true, "1.4K", "1K", "1.5K", "1K"); + test_format_bytes_one(UINT64_C(3)*1024*1024, true, "3.0M", "3M", "3.1M", "3M"); + test_format_bytes_one(UINT64_C(3)*1024*1024*1024, true, "3.0G", "3G", "3.2G", "3G"); + test_format_bytes_one(UINT64_C(3)*1024*1024*1024*1024, true, "3.0T", "3T", "3.2T", "3T"); + test_format_bytes_one(UINT64_C(3)*1024*1024*1024*1024*1024, true, "3.0P", "3P", "3.3P", "3P"); + test_format_bytes_one(UINT64_C(3)*1024*1024*1024*1024*1024*1024, true, "3.0E", "3E", "3.4E", "3E"); + test_format_bytes_one(UINT64_MAX, true, NULL, NULL, NULL, NULL); + test_format_bytes_one(UINT64_MAX, false, NULL, NULL, NULL, NULL); +} + +int main(void) { + test_format_bytes(); + + return 0; +} diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index f0f015056e..7cf4f4976b 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -15,6 +15,7 @@ #include "strv.h" #include "tests.h" #include "tmpfile-util.h" +#include "umask-util.h" #include "user-util.h" #include "util.h" #include "virt.h" @@ -635,7 +636,6 @@ static void test_touch_file(void) { assert_se(st.st_uid == test_uid); assert_se(st.st_gid == test_gid); assert_se(S_ISLNK(st.st_mode)); - assert_se((st.st_mode & 0777) == 0640); assert_se(timespec_load(&st.st_mtim) == test_mtime); } @@ -746,22 +746,67 @@ static void test_rename_noreplace(void) { } } +static void test_chmod_and_chown(void) { + _cleanup_(rm_rf_physical_and_freep) char *d = NULL; + _unused_ _cleanup_umask_ mode_t u = umask(0000); + struct stat st; + const char *p; + + if (geteuid() != 0) + return; + + log_info("/* %s */", __func__); + + assert_se(mkdtemp_malloc(NULL, &d) >= 0); + + p = strjoina(d, "/reg"); + assert_se(mknod(p, S_IFREG | 0123, 0) >= 0); + + assert_se(chmod_and_chown(p, S_IFREG | 0321, 1, 2) >= 0); + assert_se(chmod_and_chown(p, S_IFDIR | 0555, 3, 4) == -EINVAL); + + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISREG(st.st_mode)); + assert_se((st.st_mode & 07777) == 0321); + + p = strjoina(d, "/dir"); + assert_se(mkdir(p, 0123) >= 0); + + assert_se(chmod_and_chown(p, S_IFDIR | 0321, 1, 2) >= 0); + assert_se(chmod_and_chown(p, S_IFREG | 0555, 3, 4) == -EINVAL); + + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se((st.st_mode & 07777) == 0321); + + p = strjoina(d, "/lnk"); + assert_se(symlink("idontexist", p) >= 0); + + assert_se(chmod_and_chown(p, S_IFLNK | 0321, 1, 2) >= 0); + assert_se(chmod_and_chown(p, S_IFREG | 0555, 3, 4) == -EINVAL); + assert_se(chmod_and_chown(p, S_IFDIR | 0555, 3, 4) == -EINVAL); + + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); arg_test_dir = argv[1]; + test_chase_symlinks(); test_unlink_noerrno(); - test_get_files_in_directory(); test_readlink_and_make_absolute(); + test_get_files_in_directory(); test_var_tmp(); - test_chase_symlinks(); test_dot_or_dot_dot(); test_access_fd(); test_touch_file(); test_unlinkat_deallocate(); test_fsync_directory_of_file(); test_rename_noreplace(); + test_chmod_and_chown(); return 0; } diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index fdb0c7e87f..57cf89ff53 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -831,6 +831,31 @@ static void test_hashmap_free(void) { } } +typedef struct Item { + int seen; +} Item; +static void item_seen(Item *item) { + item->seen++; +} + +static void test_hashmap_free_with_destructor(void) { + Hashmap *m; + struct Item items[4] = {}; + unsigned i; + + log_info("/* %s */", __func__); + + assert_se(m = hashmap_new(NULL)); + for (i = 0; i < ELEMENTSOF(items) - 1; i++) + assert_se(hashmap_put(m, INT_TO_PTR(i), items + i) == 1); + + m = hashmap_free_with_destructor(m, item_seen); + assert_se(items[0].seen == 1); + assert_se(items[1].seen == 1); + assert_se(items[2].seen == 1); + assert_se(items[3].seen == 0); +} + static void test_hashmap_first(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; @@ -978,9 +1003,65 @@ static void test_hashmap_reserve(void) { assert_se(hashmap_reserve(m, UINT_MAX - 1) == -ENOMEM); } +static void test_path_hashmap(void) { + _cleanup_hashmap_free_ Hashmap *h = NULL; + + log_info("/* %s */", __func__); + + assert_se(h = hashmap_new(&path_hash_ops)); + + assert_se(hashmap_put(h, "foo", INT_TO_PTR(1)) >= 0); + assert_se(hashmap_put(h, "/foo", INT_TO_PTR(2)) >= 0); + assert_se(hashmap_put(h, "//foo", INT_TO_PTR(3)) == -EEXIST); + assert_se(hashmap_put(h, "//foox/", INT_TO_PTR(4)) >= 0); + assert_se(hashmap_put(h, "/foox////", INT_TO_PTR(5)) == -EEXIST); + assert_se(hashmap_put(h, "foo//////bar/quux//", INT_TO_PTR(6)) >= 0); + assert_se(hashmap_put(h, "foo/bar//quux/", INT_TO_PTR(8)) == -EEXIST); + + assert_se(hashmap_get(h, "foo") == INT_TO_PTR(1)); + assert_se(hashmap_get(h, "foo/") == INT_TO_PTR(1)); + assert_se(hashmap_get(h, "foo////") == INT_TO_PTR(1)); + assert_se(hashmap_get(h, "/foo") == INT_TO_PTR(2)); + assert_se(hashmap_get(h, "//foo") == INT_TO_PTR(2)); + assert_se(hashmap_get(h, "/////foo////") == INT_TO_PTR(2)); + assert_se(hashmap_get(h, "/////foox////") == INT_TO_PTR(4)); + assert_se(hashmap_get(h, "/foox/") == INT_TO_PTR(4)); + assert_se(hashmap_get(h, "/foox") == INT_TO_PTR(4)); + assert_se(!hashmap_get(h, "foox")); + assert_se(hashmap_get(h, "foo/bar/quux") == INT_TO_PTR(6)); + assert_se(hashmap_get(h, "foo////bar////quux/////") == INT_TO_PTR(6)); + assert_se(!hashmap_get(h, "/foo////bar////quux/////")); +} + +static void test_string_strv_hashmap(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + char **s; + + log_info("/* %s */", __func__); + + assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 1); + assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 0); + assert_se(string_strv_hashmap_put(&m, "foo", "BAR") == 1); + assert_se(string_strv_hashmap_put(&m, "foo", "BAR") == 0); + assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 0); + assert_se(hashmap_contains(m, "foo")); + + s = hashmap_get(m, "foo"); + assert_se(strv_equal(s, STRV_MAKE("bar", "BAR"))); + + assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 1); + assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 0); + assert_se(string_strv_hashmap_put(&m, "xxx", "BAR") == 1); + assert_se(string_strv_hashmap_put(&m, "xxx", "BAR") == 0); + assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 0); + assert_se(hashmap_contains(m, "xxx")); + + s = hashmap_get(m, "xxx"); + assert_se(strv_equal(s, STRV_MAKE("bar", "BAR"))); +} + void test_hashmap_funcs(void) { - log_parse_environment(); - log_open(); + log_info("/************ %s ************/", __func__); test_hashmap_copy(); test_hashmap_get_strv(); @@ -1005,6 +1086,7 @@ void test_hashmap_funcs(void) { test_hashmap_size(); test_hashmap_many(); test_hashmap_free(); + test_hashmap_free_with_destructor(); test_hashmap_first(); test_hashmap_first_key(); test_hashmap_steal_first_key(); @@ -1012,4 +1094,6 @@ void test_hashmap_funcs(void) { test_hashmap_clear_free_free(); test_hashmap_clear_free_with_destructor(); test_hashmap_reserve(); + test_path_hashmap(); + test_string_strv_hashmap(); } diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c index ee4c0e66db..1a6e8ffa58 100644 --- a/src/test/test-hashmap.c +++ b/src/test/test-hashmap.c @@ -31,31 +31,6 @@ static void test_ordered_hashmap_next(void) { assert_se(!ordered_hashmap_next(m, INT_TO_PTR(3))); } -typedef struct Item { - int seen; -} Item; -static void item_seen(Item *item) { - item->seen++; -} - -static void test_hashmap_free_with_destructor(void) { - Hashmap *m; - struct Item items[4] = {}; - unsigned i; - - log_info("/* %s */", __func__); - - assert_se(m = hashmap_new(NULL)); - for (i = 0; i < ELEMENTSOF(items) - 1; i++) - assert_se(hashmap_put(m, INT_TO_PTR(i), items + i) == 1); - - m = hashmap_free_with_destructor(m, item_seen); - assert_se(items[0].seen == 1); - assert_se(items[1].seen == 1); - assert_se(items[2].seen == 1); - assert_se(items[3].seen == 0); -} - static void test_uint64_compare_func(void) { const uint64_t a = 0x100, b = 0x101; @@ -134,47 +109,24 @@ static void test_iterated_cache(void) { assert_se(iterated_cache_free(c) == NULL); } -static void test_path_hashmap(void) { - _cleanup_hashmap_free_ Hashmap *h = NULL; +int main(int argc, const char *argv[]) { + /* This file tests in test-hashmap-plain.c, and tests in test-hashmap-ordered.c, which is generated + * from test-hashmap-plain.c. Hashmap tests should be added to test-hashmap-plain.c, and here only if + * they don't apply to ordered hashmaps. */ - log_info("/* %s */", __func__); + log_parse_environment(); + log_open(); - assert_se(h = hashmap_new(&path_hash_ops)); - - assert_se(hashmap_put(h, "foo", INT_TO_PTR(1)) >= 0); - assert_se(hashmap_put(h, "/foo", INT_TO_PTR(2)) >= 0); - assert_se(hashmap_put(h, "//foo", INT_TO_PTR(3)) == -EEXIST); - assert_se(hashmap_put(h, "//foox/", INT_TO_PTR(4)) >= 0); - assert_se(hashmap_put(h, "/foox////", INT_TO_PTR(5)) == -EEXIST); - assert_se(hashmap_put(h, "foo//////bar/quux//", INT_TO_PTR(6)) >= 0); - assert_se(hashmap_put(h, "foo/bar//quux/", INT_TO_PTR(8)) == -EEXIST); - - assert_se(hashmap_get(h, "foo") == INT_TO_PTR(1)); - assert_se(hashmap_get(h, "foo/") == INT_TO_PTR(1)); - assert_se(hashmap_get(h, "foo////") == INT_TO_PTR(1)); - assert_se(hashmap_get(h, "/foo") == INT_TO_PTR(2)); - assert_se(hashmap_get(h, "//foo") == INT_TO_PTR(2)); - assert_se(hashmap_get(h, "/////foo////") == INT_TO_PTR(2)); - assert_se(hashmap_get(h, "/////foox////") == INT_TO_PTR(4)); - assert_se(hashmap_get(h, "/foox/") == INT_TO_PTR(4)); - assert_se(hashmap_get(h, "/foox") == INT_TO_PTR(4)); - assert_se(!hashmap_get(h, "foox")); - assert_se(hashmap_get(h, "foo/bar/quux") == INT_TO_PTR(6)); - assert_se(hashmap_get(h, "foo////bar////quux/////") == INT_TO_PTR(6)); - assert_se(!hashmap_get(h, "/foo////bar////quux/////")); -} - -int main(int argc, const char *argv[]) { test_hashmap_funcs(); test_ordered_hashmap_funcs(); + log_info("/************ non-shared tests ************/"); + test_ordered_hashmap_next(); - test_hashmap_free_with_destructor(); test_uint64_compare_func(); test_trivial_compare_func(); test_string_compare_func(); test_iterated_cache(); - test_path_hashmap(); return 0; } diff --git a/src/test/test-id128.c b/src/test/test-id128.c index 8840788310..eea0765b7a 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) { assert_se(streq(q, UUID_WALDI)); b = mfree(b); - assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36); + assert_se(asprintf(&b, SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36); printf("waldi4: %s\n", b); assert_se(streq(q, b)); diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index cfddfe19a7..323e1124ba 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -112,7 +112,7 @@ static void test_basic_mask_and_enable(const char *root) { 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 */ + /* Disabling a disabled unit must succeed 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); diff --git a/src/test/test-journal-importer.c b/src/test/test-journal-importer.c index cddbfa7022..7e898735c9 100644 --- a/src/test/test-journal-importer.c +++ b/src/test/test-journal-importer.c @@ -21,7 +21,7 @@ static void assert_iovec_entry(const struct iovec *iovec, const char* content) { "0::/user.slice/user-1002.slice/user@1002.service/gnome-terminal-server.service\n" static void test_basic_parsing(void) { - _cleanup_(journal_importer_cleanup) JournalImporter imp = {}; + _cleanup_(journal_importer_cleanup) JournalImporter imp = JOURNAL_IMPORTER_INIT(-1); _cleanup_free_ char *journal_data_path = NULL; int r; @@ -52,7 +52,7 @@ static void test_basic_parsing(void) { } static void test_bad_input(void) { - _cleanup_(journal_importer_cleanup) JournalImporter imp = {}; + _cleanup_(journal_importer_cleanup) JournalImporter imp = JOURNAL_IMPORTER_INIT(-1); _cleanup_free_ char *journal_data_path = NULL; int r; diff --git a/src/test/test-json.c b/src/test/test-json.c index 9b8a2a9422..a6613043b9 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "fd-util.h" +#include "fileio.h" #include "json-internal.h" #include "json.h" #include "string-util.h" @@ -88,6 +89,7 @@ static void test_variant(const char *data, Test test) { r = json_variant_format(v, 0, &s); assert_se(r >= 0); assert_se(s); + assert_se((size_t) r == strlen(s)); log_info("formatted normally: %s\n", s); @@ -104,6 +106,7 @@ static void test_variant(const char *data, Test test) { r = json_variant_format(v, JSON_FORMAT_PRETTY, &s); assert_se(r >= 0); assert_se(s); + assert_se((size_t) r == strlen(s)); log_info("formatted prettily:\n%s", s); @@ -119,12 +122,14 @@ static void test_variant(const char *data, Test test) { r = json_variant_format(v, JSON_FORMAT_COLOR, &s); assert_se(r >= 0); assert_se(s); + assert_se((size_t) r == strlen(s)); printf("Normal with color: %s\n", s); s = mfree(s); r = json_variant_format(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, &s); assert_se(r >= 0); assert_se(s); + assert_se((size_t) r == strlen(s)); printf("Pretty with color:\n%s\n", s); if (test) @@ -358,7 +363,7 @@ static void test_source(void) { "%s" "--- original end ---\n", data); - assert_se(f = fmemopen((void*) data, strlen(data), "r")); + assert_se(f = fmemopen_unlocked((void*) data, strlen(data), "r")); assert_se(json_parse_file(f, "waldo", &v, NULL, NULL) >= 0); diff --git a/src/test/test-libmount.c b/src/test/test-libmount.c index fc28f27d53..c3395493d4 100644 --- a/src/test/test-libmount.c +++ b/src/test/test-libmount.c @@ -21,13 +21,10 @@ static void test_libmount_unescaping_one( _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL; _cleanup_fclose_ FILE *f = NULL; - assert_se(table = mnt_new_table()); - assert_se(iter = mnt_new_iter(MNT_ITER_FORWARD)); - f = fmemopen((char*) string, strlen(string), "re"); assert_se(f); - assert_se(mnt_table_parse_stream(table, f, title) >= 0); + assert_se(libmount_parse(title, f, &table, &iter) >= 0); struct libmnt_fs *fs; const char *source, *target; diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index f634ca28db..dcb5bcc254 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -158,7 +158,7 @@ static int enumerate_print_list(struct udev_enumerate *enumerate) { device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), udev_list_entry_get_name(list_entry)); - if (device != NULL) { + if (device) { log_info("device: '%s' (%s)", udev_device_get_syspath(device), udev_device_get_subsystem(device)); @@ -249,7 +249,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_add_match_subsystem(udev_enumerate, subsystem); udev_enumerate_scan_devices(udev_enumerate); @@ -258,7 +258,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate 'net' + duplicated scan + null + zero"); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_add_match_subsystem(udev_enumerate, "net"); udev_enumerate_scan_devices(udev_enumerate); @@ -278,7 +278,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate 'block'"); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_add_match_subsystem(udev_enumerate,"block"); r = udev_enumerate_add_match_is_initialized(udev_enumerate); @@ -292,7 +292,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate 'not block'"); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block"); udev_enumerate_scan_devices(udev_enumerate); @@ -301,7 +301,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate 'pci, mem, vc'"); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_add_match_subsystem(udev_enumerate, "pci"); udev_enumerate_add_match_subsystem(udev_enumerate, "mem"); @@ -312,7 +312,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate 'subsystem'"); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_scan_subsystems(udev_enumerate); enumerate_print_list(udev_enumerate); @@ -320,7 +320,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { log_info("enumerate 'property IF_FS_*=filesystem'"); udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) + if (!udev_enumerate) return -1; udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem"); udev_enumerate_scan_devices(udev_enumerate); @@ -433,19 +433,20 @@ static void test_util_resolve_subsys_kernel(void) { } static void test_list(void) { - struct udev_list list = {}; + _cleanup_(udev_list_freep) struct udev_list *list = NULL; struct udev_list_entry *e; /* empty list */ - udev_list_init(&list, false); - assert_se(!udev_list_get_entry(&list)); + assert_se(list = udev_list_new(false)); + assert_se(!udev_list_get_entry(list)); + list = udev_list_free(list); /* unique == false */ - udev_list_init(&list, false); - assert_se(udev_list_entry_add(&list, "aaa", "hoge")); - assert_se(udev_list_entry_add(&list, "aaa", "hogehoge")); - assert_se(udev_list_entry_add(&list, "bbb", "foo")); - e = udev_list_get_entry(&list); + assert_se(list = udev_list_new(false)); + assert_se(udev_list_entry_add(list, "aaa", "hoge")); + assert_se(udev_list_entry_add(list, "aaa", "hogehoge")); + assert_se(udev_list_entry_add(list, "bbb", "foo")); + e = udev_list_get_entry(list); assert_se(e); assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); assert_se(streq_ptr(udev_list_entry_get_value(e), "hoge")); @@ -462,14 +463,14 @@ static void test_list(void) { assert_se(!udev_list_entry_get_by_name(e, "aaa")); assert_se(!udev_list_entry_get_by_name(e, "bbb")); assert_se(!udev_list_entry_get_by_name(e, "ccc")); - udev_list_cleanup(&list); + list = udev_list_free(list); /* unique == true */ - udev_list_init(&list, true); - assert_se(udev_list_entry_add(&list, "aaa", "hoge")); - assert_se(udev_list_entry_add(&list, "aaa", "hogehoge")); - assert_se(udev_list_entry_add(&list, "bbb", "foo")); - e = udev_list_get_entry(&list); + assert_se(list = udev_list_new(true)); + assert_se(udev_list_entry_add(list, "aaa", "hoge")); + assert_se(udev_list_entry_add(list, "aaa", "hogehoge")); + assert_se(udev_list_entry_add(list, "bbb", "foo")); + e = udev_list_get_entry(list); assert_se(e); assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); assert_se(streq_ptr(udev_list_entry_get_value(e), "hogehoge")); @@ -487,7 +488,6 @@ static void test_list(void) { assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); assert_se(streq_ptr(udev_list_entry_get_value(e), "hogehoge")); assert_se(!udev_list_entry_get_by_name(e, "ccc")); - udev_list_cleanup(&list); } static int parse_args(int argc, char *argv[], const char **syspath, const char **subsystem) { diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c new file mode 100644 index 0000000000..8deaf4eb0f --- /dev/null +++ b/src/test/test-load-fragment.c @@ -0,0 +1,801 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/capability.h> +#include <unistd.h> + +#include "all-units.h" +#include "alloc-util.h" +#include "capability-util.h" +#include "conf-parser.h" +#include "fd-util.h" +#include "format-util.h" +#include "fs-util.h" +#include "hashmap.h" +#include "hostname-util.h" +#include "install-printf.h" +#include "install.h" +#include "load-fragment.h" +#include "macro.h" +#include "memory-util.h" +#include "rm-rf.h" +#include "specifier.h" +#include "string-util.h" +#include "strv.h" +#include "test-helper.h" +#include "tests.h" +#include "tmpfile-util.h" +#include "user-util.h" + +static int test_unit_file_get_set(void) { + int r; + Hashmap *h; + Iterator i; + UnitFileList *p; + + h = hashmap_new(&string_hash_ops); + assert_se(h); + + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); + if (IN_SET(r, -EPERM, -EACCES)) + return log_tests_skipped_errno(r, "unit_file_get_list"); + + log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r, + "unit_file_get_list: %m"); + if (r < 0) + return EXIT_FAILURE; + + HASHMAP_FOREACH(p, h, i) + printf("%s = %s\n", p->path, unit_file_state_to_string(p->state)); + + unit_file_list_free(h); + + return 0; +} + +static void check_execcommand(ExecCommand *c, + const char* path, + const char* argv0, + const char* argv1, + const char* argv2, + bool ignore) { + size_t n; + + assert_se(c); + log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]", + path, argv0 ?: path, argv1, argv2); + n = strv_length(c->argv); + log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]", + c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL); + assert_se(streq(c->path, path)); + assert_se(streq(c->argv[0], argv0 ?: path)); + if (n > 0) + assert_se(streq_ptr(c->argv[1], argv1)); + if (n > 1) + assert_se(streq_ptr(c->argv[2], argv2)); + assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore); +} + +static void test_config_parse_exec(void) { + /* int config_parse_exec( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + int r; + + ExecCommand *c = NULL, *c1; + const char *ccc; + _cleanup_(manager_freep) Manager *m = NULL; + _cleanup_(unit_freep) Unit *u = NULL; + + r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; + } + + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + assert_se(u = unit_new(m, sizeof(Service))); + + log_info("/* basic test */"); + r = config_parse_exec(NULL, "fake", 1, "section", 1, + "LValue", 0, "/RValue r1", + &c, u); + assert_se(r >= 0); + check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false); + + r = config_parse_exec(NULL, "fake", 2, "section", 1, + "LValue", 0, "/RValue///slashes r1///", + &c, u); + + log_info("/* test slashes */"); + assert_se(r >= 0); + c1 = c->command_next; + check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false); + + log_info("/* trailing slash */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/RValue/ argv0 r1", + &c, u); + assert_se(r == -ENOEXEC); + assert_se(c1->command_next == NULL); + + log_info("/* honour_argv0 */"); + r = config_parse_exec(NULL, "fake", 3, "section", 1, + "LValue", 0, "@/RValue///slashes2 ///argv0 r1", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false); + + log_info("/* honour_argv0, no args */"); + r = config_parse_exec(NULL, "fake", 3, "section", 1, + "LValue", 0, "@/RValue", + &c, u); + assert_se(r == -ENOEXEC); + assert_se(c1->command_next == NULL); + + log_info("/* no command, whitespace only, reset */"); + r = config_parse_exec(NULL, "fake", 3, "section", 1, + "LValue", 0, " ", + &c, u); + assert_se(r == 0); + assert_se(c == NULL); + + log_info("/* ignore && honour_argv0 */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "-@/RValue///slashes3 argv0a r1", + &c, u); + assert_se(r >= 0); + c1 = c; + check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true); + + log_info("/* ignore && honour_argv0 */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "@-/RValue///slashes4 argv0b r1", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true); + + log_info("/* ignore && ignore */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "--/RValue argv0 r1", + &c, u); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + log_info("/* ignore && ignore (2) */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "-@-/RValue argv0 r1", + &c, u); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + log_info("/* semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; " + "/goo/goo boo", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + c1 = c1->command_next; + check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false); + + log_info("/* two semicolons in a row */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; ; " + "/goo/goo boo", + &c, u); + assert_se(r == -ENOEXEC); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + /* second command fails because the executable name is ";" */ + assert_se(c1->command_next == NULL); + + log_info("/* trailing semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; ", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + assert_se(c1->command_next == NULL); + + log_info("/* trailing semicolon, no whitespace */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ;", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + assert_se(c1->command_next == NULL); + + log_info("/* trailing semicolon in single quotes */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ';'", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", ";", true); + + log_info("/* escaped semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/bin/find \\;", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + + log_info("/* escaped semicolon with following arg */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/sbin/find \\; /x", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/sbin/find", NULL, ";", "/x", false); + + log_info("/* escaped semicolon as part of an expression */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/sbin/find \\;x", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/sbin/find", NULL, "\\;x", NULL, false); + + log_info("/* encoded semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/bin/find \\073", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + + log_info("/* quoted semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/bin/find \";\"", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + + log_info("/* quoted semicolon with following arg */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/sbin/find \";\" /x", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/sbin/find", NULL, ";", "/x", false); + + log_info("/* spaces in the filename */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH WITH SPACES/daemon\" -1 -2", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false); + + log_info("/* spaces in the filename, no args */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH WITH SPACES/daemon -1 -2\"", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false); + + log_info("/* spaces in the filename, everything quoted */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false); + + log_info("/* escaped spaces in the filename */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false); + + log_info("/* escaped spaces in the filename (2) */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false); + + for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) { + /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */ + char path[] = "/path\\X"; + path[sizeof(path) - 2] = *ccc; + + log_info("/* invalid character: \\%c */", *ccc); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, path, + &c, u); + assert_se(r == -ENOEXEC); + assert_se(c1->command_next == NULL); + } + + log_info("/* valid character: \\s */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/path\\s", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/path ", NULL, NULL, NULL, false); + + log_info("/* quoted backslashes */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/bin/grep '\\w+\\K'", + &c, u); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false); + + log_info("/* trailing backslash: \\ */"); + /* backslash is invalid */ + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/path\\", + &c, u); + assert_se(r == -ENOEXEC); + assert_se(c1->command_next == NULL); + + log_info("/* missing ending ' */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/path 'foo", + &c, u); + assert_se(r == -ENOEXEC); + assert_se(c1->command_next == NULL); + + log_info("/* missing ending ' with trailing backslash */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/path 'foo\\", + &c, u); + assert_se(r == -ENOEXEC); + assert_se(c1->command_next == NULL); + + log_info("/* invalid space between modifiers */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "- /path", + &c, u); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + log_info("/* only modifiers, no path */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "-", + &c, u); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + log_info("/* empty argument, reset */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "", + &c, u); + assert_se(r == 0); + assert_se(c == NULL); + + exec_command_free_list(c); +} + +static void test_config_parse_log_extra_fields(void) { + /* int config_parse_log_extra_fields( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + + int r; + + _cleanup_(manager_freep) Manager *m = NULL; + _cleanup_(unit_freep) Unit *u = NULL; + ExecContext c = {}; + + r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; + } + + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + assert_se(u = unit_new(m, sizeof(Service))); + + log_info("/* %s – basic test */", __func__); + r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1, + "LValue", 0, "FOO=BAR \"QOOF=quux ' ' \"", + &c, u); + assert_se(r >= 0); + assert_se(c.n_log_extra_fields == 2); + assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len)); + assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len)); + + log_info("/* %s – add some */", __func__); + r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1, + "LValue", 0, "FOO2=BAR2 QOOF2=quux ' '", + &c, u); + assert_se(r >= 0); + assert_se(c.n_log_extra_fields == 4); + assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len)); + assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len)); + assert_se(strneq(c.log_extra_fields[2].iov_base, "FOO2=BAR2", c.log_extra_fields[2].iov_len)); + assert_se(strneq(c.log_extra_fields[3].iov_base, "QOOF2=quux", c.log_extra_fields[3].iov_len)); + + exec_context_dump(&c, stdout, " --> "); + + log_info("/* %s – reset */", __func__); + r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1, + "LValue", 0, "", + &c, u); + assert_se(r >= 0); + assert_se(c.n_log_extra_fields == 0); + + exec_context_free_log_extra_fields(&c); + + log_info("/* %s – bye */", __func__); +} + +static void test_install_printf(void) { + char name[] = "name.service", + path[] = "/run/systemd/system/name.service"; + UnitFileInstallInfo i = { .name = name, .path = path, }; + UnitFileInstallInfo i2 = { .name= name, .path = path, }; + char name3[] = "name@inst.service", + path3[] = "/run/systemd/system/name.service"; + UnitFileInstallInfo i3 = { .name = name3, .path = path3, }; + UnitFileInstallInfo i4 = { .name = name3, .path = path3, }; + + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL; + + assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); + assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); + assert_se(host = gethostname_malloc()); + assert_se(group = gid_to_name(getgid())); + assert_se(asprintf(&gid, UID_FMT, getgid()) >= 0); + assert_se(user = uid_to_name(getuid())); + assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); + +#define expect(src, pattern, result) \ + do { \ + _cleanup_free_ char *t = NULL; \ + _cleanup_free_ char \ + *d1 = strdup(i.name), \ + *d2 = strdup(i.path); \ + assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \ + memzero(i.name, strlen(i.name)); \ + memzero(i.path, strlen(i.path)); \ + assert_se(d1 && d2); \ + if (result) { \ + printf("%s\n", t); \ + assert_se(streq(t, result)); \ + } else assert_se(t == NULL); \ + strcpy(i.name, d1); \ + strcpy(i.path, d2); \ + } while (false) + + expect(i, "%n", "name.service"); + expect(i, "%N", "name"); + expect(i, "%p", "name"); + expect(i, "%i", ""); + expect(i, "%j", "name"); + expect(i, "%g", group); + expect(i, "%G", gid); + expect(i, "%u", user); + expect(i, "%U", uid); + + expect(i, "%m", mid); + expect(i, "%b", bid); + expect(i, "%H", host); + + expect(i2, "%g", group); + expect(i2, "%G", gid); + expect(i2, "%u", user); + expect(i2, "%U", uid); + + expect(i3, "%n", "name@inst.service"); + expect(i3, "%N", "name@inst"); + expect(i3, "%p", "name"); + expect(i3, "%g", group); + expect(i3, "%G", gid); + expect(i3, "%u", user); + expect(i3, "%U", uid); + + expect(i3, "%m", mid); + expect(i3, "%b", bid); + expect(i3, "%H", host); + + expect(i4, "%g", group); + expect(i4, "%G", gid); + expect(i4, "%u", user); + expect(i4, "%U", uid); +} + +static uint64_t make_cap(int cap) { + return ((uint64_t) 1ULL << (uint64_t) cap); +} + +static void test_config_parse_capability_set(void) { + /* int config_parse_capability_set( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + int r; + uint64_t capability_bounding_set = 0; + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_RAW", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == UINT64_C(0)); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "~", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(cap_test_all(capability_bounding_set)); + + capability_bounding_set = 0; + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); +} + +static void test_config_parse_rlimit(void) { + struct rlimit * rl[_RLIMIT_MAX] = {}; + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + rl[RLIMIT_NOFILE]->rlim_cur = 10; + rl[RLIMIT_NOFILE]->rlim_max = 20; + + /* Invalid values don't change rl */ + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 40); + assert_se(rl[RLIMIT_CPU]->rlim_max == 60); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]); +} + +static void test_config_parse_pass_environ(void) { + /* int config_parse_pass_environ( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + int r; + _cleanup_strv_free_ char **passenv = NULL; + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "A B", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_length(passenv) == 2); + assert_se(streq(passenv[0], "A")); + assert_se(streq(passenv[1], "B")); + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_isempty(passenv)); + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_length(passenv) == 1); + assert_se(streq(passenv[0], "normal_name")); + +} + +static void test_unit_dump_config_items(void) { + unit_dump_config_items(stdout); +} + +int main(int argc, char *argv[]) { + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; + int r; + + test_setup_logging(LOG_INFO); + + r = enter_cgroup_subroot(); + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); + + assert_se(runtime_dir = setup_fake_runtime_dir()); + + r = test_unit_file_get_set(); + test_config_parse_exec(); + test_config_parse_log_extra_fields(); + test_config_parse_capability_set(); + test_config_parse_rlimit(); + test_config_parse_pass_environ(); + TEST_REQ_RUNNING_SYSTEMD(test_install_printf()); + test_unit_dump_config_items(); + + return r; +} diff --git a/src/test/test-local-addresses.c b/src/test/test-local-addresses.c new file mode 100644 index 0000000000..37505ea783 --- /dev/null +++ b/src/test/test-local-addresses.c @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <stdio.h> + +#include "af-list.h" +#include "alloc-util.h" +#include "in-addr-util.h" +#include "local-addresses.h" +#include "tests.h" + +static void print_local_addresses(struct local_address *a, unsigned n) { + unsigned i; + + for (i = 0; i < n; i++) { + _cleanup_free_ char *b = NULL; + + assert_se(in_addr_to_string(a[i].family, &a[i].address, &b) >= 0); + printf("%s if%i scope=%i metric=%u address=%s\n", af_to_name(a[i].family), a[i].ifindex, a[i].scope, a[i].metric, b); + } +} + +int main(int argc, char *argv[]) { + struct local_address *a; + int n; + + test_setup_logging(LOG_DEBUG); + + a = NULL; + n = local_addresses(NULL, 0, AF_UNSPEC, &a); + assert_se(n >= 0); + + printf("Local Addresses:\n"); + print_local_addresses(a, (unsigned) n); + a = mfree(a); + + n = local_gateways(NULL, 0, AF_UNSPEC, &a); + assert_se(n >= 0); + + printf("Local Gateways:\n"); + print_local_addresses(a, (unsigned) n); + free(a); + + return 0; +} diff --git a/src/test/test-log.c b/src/test/test-log.c index 18ef56ac39..c1f2f8b09d 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -6,6 +6,7 @@ #include "format-util.h" #include "log.h" #include "process-util.h" +#include "string-util.h" #include "util.h" assert_cc(LOG_REALM_REMOVE_LEVEL(LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, LOG_FTP | LOG_DEBUG)) @@ -26,6 +27,14 @@ assert_cc(!IS_SYNTHETIC_ERRNO(0)); #define X100(x) X10(X10(x)) #define X1000(x) X100(X10(x)) +static void test_file(void) { + log_info("__FILE__: %s", __FILE__); + log_info("RELATIVE_SOURCE_PATH: %s", RELATIVE_SOURCE_PATH); + log_info("PROJECT_FILE: %s", PROJECT_FILE); + + assert(startswith(__FILE__, RELATIVE_SOURCE_PATH "/")); +} + static void test_log_struct(void) { log_struct(LOG_INFO, "MESSAGE=Waldo PID="PID_FMT" (no errno)", getpid_cached(), @@ -68,6 +77,8 @@ static void test_log_syntax(void) { int main(int argc, char* argv[]) { int target; + test_file(); + for (target = 0; target < _LOG_TARGET_MAX; target++) { log_set_target(target); log_open(); diff --git a/src/test/test-ns.c b/src/test/test-ns.c index d3dbb54ca1..e9233a1643 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -75,7 +75,8 @@ int main(int argc, char *argv[]) { PROTECT_HOME_NO, PROTECT_SYSTEM_NO, 0, - 0); + 0, + NULL); if (r < 0) { log_error_errno(r, "Failed to setup namespace: %m"); diff --git a/src/test/test-nss.c b/src/test/test-nss.c index 27afe36082..6ba0f6887e 100644 --- a/src/test/test-nss.c +++ b/src/test/test-nss.c @@ -8,6 +8,7 @@ #include "af-list.h" #include "alloc-util.h" #include "errno-list.h" +#include "format-util.h" #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" @@ -77,7 +78,7 @@ static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) { union in_addr_union u; int r; char family_name[DECIMAL_STR_MAX(int)]; - char ifname[IF_NAMESIZE]; + char ifname[IF_NAMESIZE + 1]; memcpy(&u, it->addr, 16); r = in_addr_to_string(it->family, &u, &a); @@ -88,7 +89,7 @@ static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) { if (it->scopeid == 0) goto numerical_index; - if (if_indextoname(it->scopeid, ifname) == NULL) { + if (!format_ifname(it->scopeid, ifname)) { log_warning_errno(errno, "if_indextoname(%d) failed: %m", it->scopeid); numerical_index: xsprintf(ifname, "%i", it->scopeid); diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index f208559358..62ebc9c923 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -22,15 +22,15 @@ static void test_paths(UnitFileScope scope) { assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); assert_se(lookup_paths_init(&lp_without_env, scope, 0, NULL) >= 0); assert_se(!strv_isempty(lp_without_env.search_path)); - assert_se(lookup_paths_reduce(&lp_without_env) >= 0); + lookup_paths_log(&lp_without_env); systemd_unit_path = strjoina(template, "/systemd-unit-path"); assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); assert_se(lookup_paths_init(&lp_with_env, scope, 0, NULL) == 0); assert_se(strv_length(lp_with_env.search_path) == 1); assert_se(streq(lp_with_env.search_path[0], systemd_unit_path)); - assert_se(lookup_paths_reduce(&lp_with_env) >= 0); - assert_se(strv_isempty(lp_with_env.search_path)); + lookup_paths_log(&lp_with_env); + assert_se(strv_equal(lp_with_env.search_path, STRV_MAKE(systemd_unit_path))); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 182991695a..ece3eb427c 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -25,6 +25,8 @@ static void test_path_simplify(const char *in, const char *out, const char *out_dot) { char *p; + log_info("/* %s */", __func__); + p = strdupa(in); assert_se(streq(path_simplify(p, false), out)); @@ -35,6 +37,8 @@ static void test_path_simplify(const char *in, const char *out, const char *out_ static void test_path(void) { _cleanup_close_ int fd = -1; + log_info("/* %s */", __func__); + test_path_compare("/goo", "/goo", 0); test_path_compare("/goo", "/goo", 0); test_path_compare("//goo", "/goo", 0); @@ -114,6 +118,8 @@ static void test_path(void) { static void test_path_equal_root(void) { /* Nail down the details of how path_equal("/", ...) works. */ + log_info("/* %s */", __func__); + assert_se(path_equal("/", "/")); assert_se(path_equal("/", "//")); @@ -156,6 +162,8 @@ static void test_path_equal_root(void) { static void test_find_binary(const char *self) { char *p; + log_info("/* %s */", __func__); + assert_se(find_binary("/bin/sh", &p) == 0); puts(p); assert_se(path_equal(p, "/bin/sh")); @@ -191,6 +199,8 @@ static void test_prefixes(void) { char s[PATH_MAX]; bool b; + log_info("/* %s */", __func__); + i = 0; PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") { log_error("---%s---", s); @@ -238,6 +248,7 @@ static void test_prefixes(void) { } static void test_path_join(void) { + log_info("/* %s */", __func__); #define test_join(expected, ...) { \ _cleanup_free_ char *z = NULL; \ @@ -283,6 +294,8 @@ static void test_path_join(void) { } static void test_fsck_exists(void) { + log_info("/* %s */", __func__); + /* Ensure we use a sane default for PATH. */ unsetenv("PATH"); @@ -296,6 +309,8 @@ static void test_fsck_exists(void) { static void test_make_relative(void) { char *result; + log_info("/* %s */", __func__); + assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0); assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0); assert_se(path_make_relative("/some/dotdot/../path", "/some/path", &result) < 0); @@ -327,7 +342,7 @@ static void test_strv_resolve(void) { search_dirs = strv_new("/dir1", "/dir2", "/dir3"); assert_se(search_dirs); STRV_FOREACH(d, search_dirs) { - char *p = strappend(tmp_dir, *d); + char *p = path_join(tmp_dir, *d); assert_se(p); assert_se(strv_push(&absolute_dirs, p) == 0); } @@ -347,6 +362,8 @@ static void test_strv_resolve(void) { static void test_path_startswith(void) { const char *p; + log_info("/* %s */", __func__); + p = path_startswith("/foo/bar/barfoo/", "/foo"); assert_se(streq_ptr(p, "bar/barfoo/")); @@ -388,21 +405,26 @@ static void test_prefix_root_one(const char *r, const char *p, const char *expec _cleanup_free_ char *s = NULL; const char *t; - assert_se(s = prefix_root(r, p)); - assert_se(streq_ptr(s, expected)); + assert_se(s = path_join(r, p)); + assert_se(path_equal_ptr(s, expected)); t = prefix_roota(r, p); assert_se(t); - assert_se(streq_ptr(t, expected)); + assert_se(path_equal_ptr(t, expected)); } static void test_prefix_root(void) { + log_info("/* %s */", __func__); + test_prefix_root_one("/", "/foo", "/foo"); test_prefix_root_one(NULL, "/foo", "/foo"); test_prefix_root_one("", "/foo", "/foo"); test_prefix_root_one("///", "/foo", "/foo"); test_prefix_root_one("/", "////foo", "/foo"); test_prefix_root_one(NULL, "////foo", "/foo"); + test_prefix_root_one("/", "foo", "/foo"); + test_prefix_root_one("", "foo", "foo"); + test_prefix_root_one(NULL, "foo", "foo"); test_prefix_root_one("/foo", "/bar", "/foo/bar"); test_prefix_root_one("/foo", "bar", "/foo/bar"); @@ -415,6 +437,8 @@ static void test_prefix_root(void) { static void test_file_in_same_dir(void) { char *t; + log_info("/* %s */", __func__); + t = file_in_same_dir("/", "a"); assert_se(streq(t, "/a")); free(t); @@ -461,12 +485,14 @@ static void test_path_extract_filename_one(const char *input, const char *output int r; r = path_extract_filename(input, &k); - log_info("%s → %s/%s [expected: %s/%s]", strnull(input), strnull(k), strerror(-r), strnull(output), strerror(-ret)); + log_info("%s → %s/%s [expected: %s/%s]", strnull(input), strnull(k), strerror_safe(r), strnull(output), strerror_safe(ret)); assert_se(streq_ptr(k, output)); assert_se(r == ret); } static void test_path_extract_filename(void) { + log_info("/* %s */", __func__); + test_path_extract_filename_one(NULL, NULL, -EINVAL); test_path_extract_filename_one("a/b/c", "c", 0); test_path_extract_filename_one("a/b/c/", "c", 0); @@ -499,6 +525,8 @@ static void test_filename_is_valid(void) { char foo[FILENAME_MAX+2]; int i; + log_info("/* %s */", __func__); + assert_se(!filename_is_valid("")); assert_se(!filename_is_valid("/bar/foo")); assert_se(!filename_is_valid("/")); @@ -516,6 +544,8 @@ static void test_filename_is_valid(void) { } static void test_hidden_or_backup_file(void) { + log_info("/* %s */", __func__); + assert_se(hidden_or_backup_file(".hidden")); assert_se(hidden_or_backup_file("..hidden")); assert_se(!hidden_or_backup_file("hidden.")); @@ -541,6 +571,8 @@ static void test_systemd_installation_has_version(const char *path) { const unsigned versions[] = {0, 231, PROJECT_VERSION, 999}; unsigned i; + log_info("/* %s */", __func__); + for (i = 0; i < ELEMENTSOF(versions); i++) { r = systemd_installation_has_version(path, versions[i]); assert_se(r >= 0); @@ -550,6 +582,7 @@ static void test_systemd_installation_has_version(const char *path) { } static void test_skip_dev_prefix(void) { + log_info("/* %s */", __func__); assert_se(streq(skip_dev_prefix("/"), "/")); assert_se(streq(skip_dev_prefix("/dev"), "")); @@ -565,6 +598,8 @@ static void test_skip_dev_prefix(void) { } static void test_empty_or_root(void) { + log_info("/* %s */", __func__); + assert_se(empty_or_root(NULL)); assert_se(empty_or_root("")); assert_se(empty_or_root("/")); @@ -578,6 +613,7 @@ static void test_empty_or_root(void) { } static void test_path_startswith_set(void) { + log_info("/* %s */", __func__); assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/bar", "/zzz"), "")); assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/", "/zzz"), "bar")); @@ -598,6 +634,28 @@ static void test_path_startswith_set(void) { assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "", "/zzz"), NULL)); } +static void test_path_startswith_strv(void) { + log_info("/* %s */", __func__); + + assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/foo/bar", "/zzz")), "")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/foo/", "/zzz")), "bar")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/foo", "/zzz")), "bar")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/", "/zzz")), "foo/bar")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "", "/zzz")), NULL)); + + assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/foo/bar", "/zzz")), NULL)); + assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/foo/", "/zzz")), "bar2")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/foo", "/zzz")), "bar2")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/", "/zzz")), "foo/bar2")); + assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "", "/zzz")), NULL)); + + assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/foo/bar", "/zzz")), NULL)); + assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/foo/", "/zzz")), NULL)); + assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/foo", "/zzz")), NULL)); + assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/", "/zzz")), "foo2/bar")); + assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "", "/zzz")), NULL)); +} + int main(int argc, char **argv) { test_setup_logging(LOG_DEBUG); @@ -619,6 +677,7 @@ int main(int argc, char **argv) { test_skip_dev_prefix(); test_empty_or_root(); test_path_startswith_set(); + test_path_startswith_strv(); test_systemd_installation_has_version(argv[1]); /* NULL is OK */ diff --git a/src/test/test-pretty-print.c b/src/test/test-pretty-print.c index 3ad80d145d..9236eb1315 100644 --- a/src/test/test-pretty-print.c +++ b/src/test/test-pretty-print.c @@ -15,7 +15,7 @@ static void test_terminal_urlify(void) { _cleanup_free_ char *formatted = NULL; assert_se(terminal_urlify("https://www.freedesktop.org/wiki/Software/systemd/", "systemd homepage", &formatted) >= 0); - printf("Hey, considere visiting the %s right now! It is very good!\n", formatted); + printf("Hey, consider visiting the %s right now! It is very good!\n", formatted); formatted = mfree(formatted); diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index 4e209de5b6..6d25a6919e 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -170,7 +170,6 @@ static void test_proc_cmdline_get_key_many(void) { "doubleticks", &value6, "zummm", &value7) == 5); - assert_se(streq_ptr(value1, "quux")); assert_se(!value2); assert_se(streq_ptr(value3, "tuet")); diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 89f6618e2e..8dc9fdda50 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -48,14 +48,14 @@ static void test_get_process_comm(pid_t pid) { } else log_warning("%s not exist.", path); - assert_se(get_process_cmdline(pid, 0, true, &c) >= 0); + assert_se(get_process_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c) >= 0); log_info("PID"PID_FMT" cmdline: '%s'", pid, c); - assert_se(get_process_cmdline(pid, 8, false, &d) >= 0); + assert_se(get_process_cmdline(pid, 8, 0, &d) >= 0); log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d); free(d); - assert_se(get_process_cmdline(pid, 1, false, &d) >= 0); + assert_se(get_process_cmdline(pid, 1, 0, &d) >= 0); log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d); assert_se(get_process_ppid(pid, &e) >= 0); @@ -107,12 +107,12 @@ static void test_get_process_comm_escape(void) { test_get_process_comm_escape_one("foo", "foo"); test_get_process_comm_escape_one("012345678901234", "012345678901234"); test_get_process_comm_escape_one("0123456789012345", "012345678901234"); - test_get_process_comm_escape_one("äöüß", "\\303\\244\\303…"); - test_get_process_comm_escape_one("xäöüß", "x\\303\\244…"); - test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244…"); - test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244…"); - test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244…"); - test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303…"); + test_get_process_comm_escape_one("äöüß", "\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xäöüß", "x\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237"); + test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237"); assert_se(prctl(PR_SET_NAME, saved) >= 0); } @@ -237,150 +237,149 @@ static void test_get_process_cmdline_harder(void) { assert_se(prctl(PR_SET_NAME, "testa") >= 0); - assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) == -ENOENT); - assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "[testa]")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), 0, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + log_info("'%s'", line); assert_se(streq(line, "")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0); - assert_se(streq(line, "[")); + assert_se(get_process_cmdline(getpid_cached(), 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0); - assert_se(streq(line, "[.")); + assert_se(get_process_cmdline(getpid_cached(), 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0); - assert_se(streq(line, "[..")); + assert_se(get_process_cmdline(getpid_cached(), 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[t…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0); - assert_se(streq(line, "[...")); + assert_se(get_process_cmdline(getpid_cached(), 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[te…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0); - assert_se(streq(line, "[...]")); + assert_se(get_process_cmdline(getpid_cached(), 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[tes…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0); - assert_se(streq(line, "[t...]")); + assert_se(get_process_cmdline(getpid_cached(), 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[test…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "[testa]")); line = mfree(line); - assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10); - - assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT); - - assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "[testa]")); line = mfree(line); - assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10); + assert_se(write(fd, "foo\0bar", 8) == 8); - assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) >= 0); + log_info("'%s'", line); assert_se(streq(line, "foo bar")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "foo bar")); line = mfree(line); assert_se(write(fd, "quux", 4) == 4); - assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) >= 0); + log_info("'%s'", line); assert_se(streq(line, "foo bar quux")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0); - assert_se(streq(line, "")); + assert_se(get_process_cmdline(getpid_cached(), 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0); - assert_se(streq(line, ".")); + assert_se(get_process_cmdline(getpid_cached(), 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "f…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0); - assert_se(streq(line, "..")); + assert_se(get_process_cmdline(getpid_cached(), 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "fo…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0); - assert_se(streq(line, "...")); + assert_se(get_process_cmdline(getpid_cached(), 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0); - assert_se(streq(line, "f...")); + assert_se(get_process_cmdline(getpid_cached(), 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo …")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0); - assert_se(streq(line, "fo...")); + assert_se(get_process_cmdline(getpid_cached(), 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo b…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0); - assert_se(streq(line, "foo...")); + assert_se(get_process_cmdline(getpid_cached(), 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo ba…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0); - assert_se(streq(line, "foo...")); + assert_se(get_process_cmdline(getpid_cached(), 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo bar…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 9, true, &line) >= 0); - assert_se(streq(line, "foo b...")); + assert_se(get_process_cmdline(getpid_cached(), 9, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo bar …")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0); - assert_se(streq(line, "foo ba...")); + assert_se(get_process_cmdline(getpid_cached(), 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo bar q…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0); - assert_se(streq(line, "foo bar...")); + assert_se(get_process_cmdline(getpid_cached(), 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo bar qu…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0); - assert_se(streq(line, "foo bar...")); + assert_se(get_process_cmdline(getpid_cached(), 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "foo bar quux")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 13, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), 13, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 14, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), 14, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 1000, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); assert_se(ftruncate(fd, 0) >= 0); assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0); - assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) == -ENOENT); - assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0); + assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); assert_se(streq(line, "[aaaa bbbb cccc]")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0); - assert_se(streq(line, "[aaaa...]")); + assert_se(get_process_cmdline(getpid_cached(), 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[aaaa bbb…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0); - assert_se(streq(line, "[aaaa...]")); + assert_se(get_process_cmdline(getpid_cached(), 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[aaaa bbbb…")); line = mfree(line); - assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0); - assert_se(streq(line, "[aaaa b...]")); + assert_se(get_process_cmdline(getpid_cached(), 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0); + assert_se(streq(line, "[aaaa bbbb …")); line = mfree(line); safe_close(fd); @@ -408,8 +407,10 @@ static void test_rename_process_now(const char *p, int ret) { assert_se(get_process_comm(0, &comm) >= 0); log_info("comm = <%s>", comm); assert_se(strneq(comm, p, TASK_COMM_LEN-1)); + /* We expect comm to be at most 16 bytes (TASK_COMM_LEN). The kernel may raise this limit in the + * future. We'd only check the initial part, at least until we recompile, but this will still pass. */ - r = get_process_cmdline(0, 0, false, &cmdline); + r = get_process_cmdline(0, SIZE_MAX, 0, &cmdline); assert_se(r >= 0); /* we cannot expect cmdline to be renamed properly without privileges */ if (geteuid() == 0) { @@ -523,14 +524,14 @@ static void test_getpid_measure(void) { (void) getpid(); q = now(CLOCK_MONOTONIC) - t; - log_info(" glibc getpid(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q)); + log_info(" glibc getpid(): %lf µs each\n", (double) q / MEASURE_ITERATIONS); t = now(CLOCK_MONOTONIC); for (i = 0; i < MEASURE_ITERATIONS; i++) (void) getpid_cached(); q = now(CLOCK_MONOTONIC) - t; - log_info("getpid_cached(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q)); + log_info("getpid_cached(): %lf µs each\n", (double) q / MEASURE_ITERATIONS); } static void test_safe_fork(void) { diff --git a/src/test/test-procfs-util.c b/src/test/test-procfs-util.c index 1d0612985b..662688e0f0 100644 --- a/src/test/test-procfs-util.c +++ b/src/test/test-procfs-util.c @@ -2,8 +2,8 @@ #include <errno.h> +#include "format-util.h" #include "log.h" -#include "parse-util.h" #include "procfs-util.h" int main(int argc, char *argv[]) { diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 9b7307cf39..a906070f9a 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -635,7 +635,7 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL, true) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c index 35b087653e..7fc16a62b6 100644 --- a/src/test/test-sizeof.c +++ b/src/test/test-sizeof.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <sched.h> #include <stdio.h> #include <string.h> @@ -65,6 +66,8 @@ int main(void) { info(uid_t); info(gid_t); + info(__cpu_mask); + info(enum Enum); info(enum BigEnum); info(enum BigEnum2); diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index e0c513ad8c..014b1aa7a2 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -7,6 +7,7 @@ #include <sys/types.h> #include <unistd.h> +#include "errno-util.h" #include "fd-util.h" #include "log.h" #include "memory-util.h" @@ -16,12 +17,29 @@ #include "util.h" static void test_parse_sleep_config(void) { - const char *verb; - + _cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL; log_info("/* %s */", __func__); - FOREACH_STRING(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate") - assert_se(parse_sleep_config(verb, NULL, NULL, NULL, NULL) == 0); + assert(parse_sleep_config(&sleep_config) == 0); + + _cleanup_free_ char *sum, *sus, *him, *his, *hym, *hys; + + sum = strv_join(sleep_config->suspend_modes, ", "); + sus = strv_join(sleep_config->suspend_states, ", "); + him = strv_join(sleep_config->hibernate_modes, ", "); + his = strv_join(sleep_config->hibernate_states, ", "); + hym = strv_join(sleep_config->hybrid_modes, ", "); + hys = strv_join(sleep_config->hybrid_states, ", "); + log_debug(" allow_suspend: %u", sleep_config->allow_suspend); + log_debug(" allow_hibernate: %u", sleep_config->allow_hibernate); + log_debug(" allow_s2h: %u", sleep_config->allow_s2h); + log_debug(" allow_hybrid_sleep: %u", sleep_config->allow_hybrid_sleep); + log_debug(" suspend modes: %s", sum); + log_debug(" states: %s", sus); + log_debug(" hibernate modes: %s", him); + log_debug(" states: %s", his); + log_debug(" hybrid modes: %s", hym); + log_debug(" states: %s", hys); } static int test_fiemap(const char *path) { @@ -61,7 +79,7 @@ static void test_sleep(void) { **reboot = strv_new("reboot"), **platform = strv_new("platform"), **shutdown = strv_new("shutdown"), - **freez = strv_new("freeze"); + **freeze = strv_new("freeze"); int r; log_info("/* %s */", __func__); @@ -74,23 +92,23 @@ static void test_sleep(void) { log_info("Hibernate+Reboot configured: %s", yes_no(can_sleep_disk(reboot) > 0)); log_info("Hibernate+Platform configured: %s", yes_no(can_sleep_disk(platform) > 0)); log_info("Hibernate+Shutdown configured: %s", yes_no(can_sleep_disk(shutdown) > 0)); - log_info("Freeze configured: %s", yes_no(can_sleep_state(freez) > 0)); + log_info("Freeze configured: %s", yes_no(can_sleep_state(freeze) > 0)); log_info("/= running system =/"); r = can_sleep("suspend"); - log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror(-r)); + log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r)); r = can_sleep("hibernate"); - log_info("Hibernation configured and possible: %s", r >= 0 ? yes_no(r) : strerror(-r)); + log_info("Hibernation configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r)); r = can_sleep("hybrid-sleep"); - log_info("Hybrid-sleep configured and possible: %s", r >= 0 ? yes_no(r) : strerror(-r)); + log_info("Hybrid-sleep configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r)); r = can_sleep("suspend-then-hibernate"); - log_info("Suspend-then-Hibernate configured and possible: %s", r >= 0 ? yes_no(r) : strerror(-r)); + log_info("Suspend-then-Hibernate configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r)); } int main(int argc, char* argv[]) { int i, r = 0, k; - test_setup_logging(LOG_INFO); + test_setup_logging(LOG_DEBUG); if (getuid() != 0) log_warning("This program is unlikely to work for unprivileged users"); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 057840d76f..4e9a0bddf4 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -810,6 +810,67 @@ static void test_send_emptydata(void) { assert_se(fd == -999); } +static void test_flush_accept(void) { + _cleanup_close_ int listen_stream = -1, listen_dgram = -1, listen_seqpacket = 1, connect_stream = -1, connect_dgram = -1, connect_seqpacket = -1; + static const union sockaddr_union sa = { .un.sun_family = AF_UNIX }; + union sockaddr_union lsa; + socklen_t l; + + listen_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(listen_stream >= 0); + + listen_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(listen_dgram >= 0); + + listen_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(listen_seqpacket >= 0); + + assert_se(flush_accept(listen_stream) < 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) < 0); + + assert_se(bind(listen_stream, &sa.sa, sizeof(sa_family_t)) >= 0); + assert_se(bind(listen_dgram, &sa.sa, sizeof(sa_family_t)) >= 0); + assert_se(bind(listen_seqpacket, &sa.sa, sizeof(sa_family_t)) >= 0); + + assert_se(flush_accept(listen_stream) < 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) < 0); + + assert_se(listen(listen_stream, SOMAXCONN) >= 0); + assert_se(listen(listen_dgram, SOMAXCONN) < 0); + assert_se(listen(listen_seqpacket, SOMAXCONN) >= 0); + + assert_se(flush_accept(listen_stream) >= 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) >= 0); + + connect_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(connect_stream >= 0); + + connect_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(connect_dgram >= 0); + + connect_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(connect_seqpacket >= 0); + + l = sizeof(lsa); + assert_se(getsockname(listen_stream, &lsa.sa, &l) >= 0); + assert_se(connect(connect_stream, &lsa.sa, l) >= 0); + + l = sizeof(lsa); + assert_se(getsockname(listen_dgram, &lsa.sa, &l) >= 0); + assert_se(connect(connect_dgram, &lsa.sa, l) >= 0); + + l = sizeof(lsa); + assert_se(getsockname(listen_seqpacket, &lsa.sa, &l) >= 0); + assert_se(connect(connect_seqpacket, &lsa.sa, l) >= 0); + + assert_se(flush_accept(listen_stream) >= 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) >= 0); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -843,6 +904,7 @@ int main(int argc, char *argv[]) { test_receive_nopassfd(); test_send_nodata_nofd(); test_send_emptydata(); + test_flush_accept(); return 0; } diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 064a5abdac..8ea3994366 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -9,29 +9,6 @@ #include "utf8.h" #include "util.h" -static void test_string_erase(void) { - char *x; - - x = strdupa(""); - assert_se(streq(string_erase(x), "")); - - x = strdupa("1"); - assert_se(streq(string_erase(x), "")); - - x = strdupa("123456789"); - assert_se(streq(string_erase(x), "")); - - assert_se(x[1] == '\0'); - assert_se(x[2] == '\0'); - assert_se(x[3] == '\0'); - assert_se(x[4] == '\0'); - assert_se(x[5] == '\0'); - assert_se(x[6] == '\0'); - assert_se(x[7] == '\0'); - assert_se(x[8] == '\0'); - assert_se(x[9] == '\0'); -} - static void test_free_and_strndup_one(char **t, const char *src, size_t l, const char *expected, bool change) { int r; @@ -273,22 +250,6 @@ static void test_strrep(void) { assert_se(streq(zero, "")); } -static void test_strappend(void) { - _cleanup_free_ char *t1, *t2, *t3, *t4; - - t1 = strappend(NULL, NULL); - assert_se(streq(t1, "")); - - t2 = strappend(NULL, "suf"); - assert_se(streq(t2, "suf")); - - t3 = strappend("pre", NULL); - assert_se(streq(t3, "pre")); - - t4 = strappend("pre", "suf"); - assert_se(streq(t4, "presuf")); -} - static void test_string_has_cc(void) { assert_se(string_has_cc("abc\1", NULL)); assert_se(string_has_cc("abc\x7f", NULL)); @@ -380,7 +341,7 @@ static void check(const char *test, char** expected, bool trailing) { for (;;) { _cleanup_free_ char *word = NULL; - r = extract_first_word(&test, &word, NULL, EXTRACT_QUOTES); + r = extract_first_word(&test, &word, NULL, EXTRACT_UNQUOTE); if (r == 0) { assert_se(!trailing); break; @@ -582,7 +543,6 @@ static void test_memory_startswith_no_case(void) { int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); - test_string_erase(); test_free_and_strndup(); test_ascii_strcasecmp_n(); test_ascii_strcasecmp_nn(); @@ -592,7 +552,6 @@ int main(int argc, char *argv[]) { test_strextend(); test_strextend_with_separator(); test_strrep(); - test_strappend(); test_string_has_cc(); test_ascii_strlower(); test_strshorten(); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 18ad03669c..5e96f3a8a7 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -23,6 +23,8 @@ static void test_specifier_printf(void) { _cleanup_free_ char *w = NULL; int r; + log_info("/* %s */", __func__); + r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w); assert_se(r >= 0); assert_se(w); @@ -38,6 +40,8 @@ static void test_specifier_printf(void) { } static void test_str_in_set(void) { + log_info("/* %s */", __func__); + assert_se(STR_IN_SET("x", "x", "y", "z")); assert_se(!STR_IN_SET("X", "x", "y", "z")); assert_se(!STR_IN_SET("", "x", "y", "z")); @@ -45,6 +49,8 @@ static void test_str_in_set(void) { } static void test_strptr_in_set(void) { + log_info("/* %s */", __func__); + assert_se(STRPTR_IN_SET("x", "x", "y", "z")); assert_se(!STRPTR_IN_SET("X", "x", "y", "z")); assert_se(!STRPTR_IN_SET("", "x", "y", "z")); @@ -57,6 +63,8 @@ static void test_strptr_in_set(void) { } static void test_startswith_set(void) { + log_info("/* %s */", __func__); + assert_se(!STARTSWITH_SET("foo", "bar", "baz", "waldo")); assert_se(!STARTSWITH_SET("foo", "bar")); @@ -105,11 +113,15 @@ static const char* const input_table_one_empty[] = { }; static void test_strv_find(void) { + log_info("/* %s */", __func__); + assert_se(strv_find((char **)input_table_multiple, "three")); assert_se(!strv_find((char **)input_table_multiple, "four")); } static void test_strv_find_prefix(void) { + log_info("/* %s */", __func__); + assert_se(strv_find_prefix((char **)input_table_multiple, "o")); assert_se(strv_find_prefix((char **)input_table_multiple, "one")); assert_se(strv_find_prefix((char **)input_table_multiple, "")); @@ -120,6 +132,8 @@ static void test_strv_find_prefix(void) { static void test_strv_find_startswith(void) { char *r; + log_info("/* %s */", __func__); + r = strv_find_startswith((char **)input_table_multiple, "o"); assert_se(r && streq(r, "ne")); @@ -136,6 +150,8 @@ static void test_strv_find_startswith(void) { static void test_strv_join(void) { _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; + log_info("/* %s */", __func__); + p = strv_join((char **)input_table_multiple, ", "); assert_se(p); assert_se(streq(p, "one, two, three")); @@ -168,6 +184,8 @@ static void test_strv_join(void) { static void test_strv_join_prefix(void) { _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; + log_info("/* %s */", __func__); + p = strv_join_prefix((char **)input_table_multiple, ", ", "foo"); assert_se(p); assert_se(streq(p, "fooone, footwo, foothree")); @@ -204,7 +222,9 @@ static void test_strv_unquote(const char *quoted, char **list) { char **t; int r; - r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); + log_info("/* %s */", __func__); + + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_UNQUOTE); assert_se(r == (int) strv_length(list)); assert_se(s); j = strv_join(s, " | "); @@ -221,66 +241,70 @@ static void test_invalid_unquote(const char *quoted) { char **s = NULL; int r; - r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); + log_info("/* %s */", __func__); + + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_UNQUOTE); assert_se(s == NULL); assert_se(r == -EINVAL); } static void test_strv_split(void) { - _cleanup_strv_free_ char **l = NULL; + _cleanup_(strv_free_erasep) char **l = NULL; const char str[] = "one,two,three"; + log_info("/* %s */", __func__); + l = strv_split(str, ","); assert_se(l); assert_se(strv_equal(l, (char**) input_table_multiple)); - strv_free(l); + strv_free_erase(l); l = strv_split(" one two\t three", WHITESPACE); assert_se(l); assert_se(strv_equal(l, (char**) input_table_multiple)); - strv_free(l); + strv_free_erase(l); /* Setting NULL for separator is equivalent to WHITESPACE */ l = strv_split(" one two\t three", NULL); assert_se(l); assert_se(strv_equal(l, (char**) input_table_multiple)); - strv_free(l); + strv_free_erase(l); l = strv_split_full(" one two\t three", NULL, 0); assert_se(l); assert_se(strv_equal(l, (char**) input_table_multiple)); - strv_free(l); + strv_free_erase(l); l = strv_split_full(" 'one' \" two\t three \" ' four five'", NULL, SPLIT_QUOTES); assert_se(l); assert_se(strv_equal(l, (char**) input_table_quoted)); - strv_free(l); + strv_free_erase(l); /* missing last quote ignores the last element. */ l = strv_split_full(" 'one' \" two\t three \" ' four five' ' ignored element ", NULL, SPLIT_QUOTES); assert_se(l); assert_se(strv_equal(l, (char**) input_table_quoted)); - strv_free(l); + strv_free_erase(l); /* missing last quote, but the last element is _not_ ignored with SPLIT_RELAX. */ l = strv_split_full(" 'one' \" two\t three \" ' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX); assert_se(l); assert_se(strv_equal(l, (char**) input_table_quoted)); - strv_free(l); + strv_free_erase(l); /* missing separator between */ l = strv_split_full(" 'one' \" two\t three \"' four five'", NULL, SPLIT_QUOTES | SPLIT_RELAX); assert_se(l); assert_se(strv_equal(l, (char**) input_table_quoted)); - strv_free(l); + strv_free_erase(l); l = strv_split_full(" 'one' \" two\t three \"' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX); assert_se(l); @@ -290,6 +314,8 @@ static void test_strv_split(void) { static void test_strv_split_empty(void) { _cleanup_strv_free_ char **l = NULL; + log_info("/* %s */", __func__); + l = strv_split("", WHITESPACE); assert_se(l); assert_se(strv_isempty(l)); @@ -355,6 +381,8 @@ static void test_strv_split_extract(void) { const char *str = ":foo\\:bar::waldo:"; int r; + log_info("/* %s */", __func__); + r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS); assert_se(r == (int) strv_length(l)); assert_se(streq_ptr(l[0], "")); @@ -371,8 +399,9 @@ static void test_strv_split_newlines(void) { _cleanup_strv_free_ char **l = NULL; const char str[] = "one\ntwo\nthree"; - l = strv_split_newlines(str); + log_info("/* %s */", __func__); + l = strv_split_newlines(str); assert_se(l); STRV_FOREACH(s, l) { @@ -384,6 +413,8 @@ static void test_strv_split_nulstr(void) { _cleanup_strv_free_ char **l = NULL; const char nulstr[] = "str0\0str1\0str2\0str3\0"; + log_info("/* %s */", __func__); + l = strv_split_nulstr (nulstr); assert_se(l); @@ -397,6 +428,8 @@ static void test_strv_parse_nulstr(void) { _cleanup_strv_free_ char **l = NULL; const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx"; + log_info("/* %s */", __func__); + l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1); assert_se(l); puts("Parse nulstr:"); @@ -429,6 +462,8 @@ static void test_strv_overlap(void) { NULL }; + log_info("/* %s */", __func__); + assert_se(strv_overlap((char **)input_table, (char**)input_table_overlap)); assert_se(!strv_overlap((char **)input_table, (char**)input_table_unique)); } @@ -443,6 +478,8 @@ static void test_strv_sort(void) { NULL }; + log_info("/* %s */", __func__); + strv_sort((char **)input_table); assert_se(streq(input_table[0], "CAPITAL LETTERS FIRST")); @@ -455,6 +492,8 @@ static void test_strv_sort(void) { static void test_strv_extend_strv_concat(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; + log_info("/* %s */", __func__); + a = strv_new("without", "suffix"); b = strv_new("with", "suffix"); assert_se(a); @@ -471,6 +510,8 @@ static void test_strv_extend_strv_concat(void) { static void test_strv_extend_strv(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL; + log_info("/* %s */", __func__); + a = strv_new("abc", "def", "ghi"); b = strv_new("jkl", "mno", "abc", "pqr"); assert_se(a); @@ -497,6 +538,8 @@ static void test_strv_extend_strv(void) { static void test_strv_extend(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; + log_info("/* %s */", __func__); + a = strv_new("test", "test1"); assert_se(a); assert_se(strv_extend(&a, "test2") >= 0); @@ -511,6 +554,8 @@ static void test_strv_extend(void) { static void test_strv_extendf(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; + log_info("/* %s */", __func__); + a = strv_new("test", "test1"); assert_se(a); assert_se(strv_extendf(&a, "test2 %s %d %s", "foo", 128, "bar") >= 0); @@ -527,13 +572,13 @@ static void test_strv_foreach(void) { unsigned i = 0; char **check; - a = strv_new("one", "two", "three"); + log_info("/* %s */", __func__); + a = strv_new("one", "two", "three"); assert_se(a); - STRV_FOREACH(check, a) { + STRV_FOREACH(check, a) assert_se(streq(*check, input_table_multiple[i++])); - } } static void test_strv_foreach_backwards(void) { @@ -541,6 +586,8 @@ static void test_strv_foreach_backwards(void) { unsigned i = 2; char **check; + log_info("/* %s */", __func__); + a = strv_new("one", "two", "three"); assert_se(a); @@ -559,19 +606,21 @@ static void test_strv_foreach_pair(void) { _cleanup_strv_free_ char **a = NULL; char **x, **y; + log_info("/* %s */", __func__); + a = strv_new("pair_one", "pair_one", "pair_two", "pair_two", "pair_three", "pair_three"); - - STRV_FOREACH_PAIR(x, y, a) { + STRV_FOREACH_PAIR(x, y, a) assert_se(streq(*x, *y)); - } } static void test_strv_from_stdarg_alloca_one(char **l, const char *first, ...) { char **j; unsigned i; + log_info("/* %s */", __func__); + j = strv_from_stdarg_alloca(first); for (i = 0;; i++) { @@ -583,6 +632,8 @@ static void test_strv_from_stdarg_alloca_one(char **l, const char *first, ...) { } static void test_strv_from_stdarg_alloca(void) { + log_info("/* %s */", __func__); + test_strv_from_stdarg_alloca_one(STRV_MAKE("foo", "bar"), "foo", "bar", NULL); test_strv_from_stdarg_alloca_one(STRV_MAKE("foo"), "foo", NULL); test_strv_from_stdarg_alloca_one(STRV_MAKE_EMPTY, NULL); @@ -591,6 +642,8 @@ static void test_strv_from_stdarg_alloca(void) { static void test_strv_insert(void) { _cleanup_strv_free_ char **a = NULL; + log_info("/* %s */", __func__); + assert_se(strv_insert(&a, 0, strdup("first")) == 0); assert_se(streq(a[0], "first")); assert_se(!a[1]); @@ -621,6 +674,8 @@ static void test_strv_insert(void) { static void test_strv_push_prepend(void) { _cleanup_strv_free_ char **a = NULL; + log_info("/* %s */", __func__); + a = strv_new("foo", "bar", "three"); assert_se(strv_push_prepend(&a, strdup("first")) >= 0); @@ -643,6 +698,8 @@ static void test_strv_push(void) { _cleanup_strv_free_ char **a = NULL; char *i, *j; + log_info("/* %s */", __func__); + assert_se(i = strdup("foo")); assert_se(strv_push(&a, i) >= 0); @@ -661,6 +718,8 @@ static void test_strv_equal(void) { _cleanup_strv_free_ char **b = NULL; _cleanup_strv_free_ char **c = NULL; + log_info("/* %s */", __func__); + a = strv_new("one", "two", "three"); assert_se(a); b = strv_new("one", "two", "three"); @@ -680,6 +739,8 @@ static void test_strv_equal(void) { static void test_strv_is_uniq(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + log_info("/* %s */", __func__); + a = strv_new(NULL); assert_se(a); assert_se(strv_is_uniq(a)); @@ -700,6 +761,8 @@ static void test_strv_is_uniq(void) { static void test_strv_reverse(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + log_info("/* %s */", __func__); + a = strv_new(NULL); assert_se(a); @@ -731,6 +794,8 @@ static void test_strv_reverse(void) { static void test_strv_shell_escape(void) { _cleanup_strv_free_ char **v = NULL; + log_info("/* %s */", __func__); + v = strv_new("foo:bar", "bar,baz", "wal\\do"); assert_se(v); assert_se(strv_shell_escape(v, ",:")); @@ -746,6 +811,8 @@ static void test_strv_skip_one(char **a, size_t n, char **b) { } static void test_strv_skip(void) { + log_info("/* %s */", __func__); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz")); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz")); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz")); @@ -765,6 +832,8 @@ static void test_strv_skip(void) { static void test_strv_extend_n(void) { _cleanup_strv_free_ char **v = NULL; + log_info("/* %s */", __func__); + v = strv_new("foo", "bar"); assert_se(v); @@ -796,6 +865,8 @@ static void test_strv_make_nulstr_one(char **l) { size_t n, m; unsigned i = 0; + log_info("/* %s */", __func__); + assert_se(strv_make_nulstr(l, &b, &n) >= 0); assert_se(q = strv_parse_nulstr(b, n)); assert_se(strv_equal(l, q)); @@ -810,6 +881,8 @@ static void test_strv_make_nulstr_one(char **l) { } static void test_strv_make_nulstr(void) { + log_info("/* %s */", __func__); + test_strv_make_nulstr_one(NULL); test_strv_make_nulstr_one(STRV_MAKE(NULL)); test_strv_make_nulstr_one(STRV_MAKE("foo")); @@ -820,6 +893,8 @@ static void test_strv_make_nulstr(void) { static void test_strv_free_free(void) { char ***t; + log_info("/* %s */", __func__); + assert_se(t = new(char**, 3)); assert_se(t[0] = strv_new("a", "b")); assert_se(t[1] = strv_new("c", "d", "e")); @@ -838,6 +913,8 @@ static void test_foreach_string(void) { const char *x; unsigned i = 0; + log_info("/* %s */", __func__); + FOREACH_STRING(x, "foo", "bar", "waldo") assert_se(streq_ptr(t[i++], x)); @@ -850,6 +927,8 @@ static void test_foreach_string(void) { static void test_strv_fnmatch(void) { _cleanup_strv_free_ char **v = NULL; + log_info("/* %s */", __func__); + assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0)); v = strv_new("*\\*"); diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c index 21d56d9be6..d7199124a3 100644 --- a/src/test/test-strxcpyx.c +++ b/src/test/test-strxcpyx.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <stdio.h> #include <string.h> #include "string-util.h" @@ -78,6 +79,24 @@ static void test_strscpyl(void) { assert_se(space_left == 10); } +static void test_sd_event_code_migration(void) { + char b[100 * DECIMAL_STR_MAX(unsigned) + 1]; + char c[100 * DECIMAL_STR_MAX(unsigned) + 1], *p; + unsigned i; + size_t l; + int o; + + for (i = o = 0; i < 100; i++) + o += snprintf(&b[o], sizeof(b) - o, "%u ", i); + + p = c; + l = sizeof(c); + for (i = 0; i < 100; i++) + l = strpcpyf(&p, l, "%u ", i); + + assert_se(streq(b, c)); +} + int main(int argc, char *argv[]) { test_strpcpy(); test_strpcpyf(); @@ -85,5 +104,7 @@ int main(int argc, char *argv[]) { test_strscpy(); test_strscpyl(); + test_sd_event_code_migration(); + return 0; } diff --git a/src/test/test-systemd-tmpfiles.py b/src/test/test-systemd-tmpfiles.py index 83a66e8772..7f4af38940 100755 --- a/src/test/test-systemd-tmpfiles.py +++ b/src/test/test-systemd-tmpfiles.py @@ -52,8 +52,8 @@ def test_invalids(*, user): test_line('w /unresolved/argument/sandwich - - - - "%v%Y%v"', user=user) test_line('w /unresolved/filename/%Y - - - - "whatever"', user=user) test_line('w /unresolved/filename/sandwich/%v%Y%v - - - - "whatever"', user=user) - test_line('w - - - - - "no file specfied"', user=user) - test_line('C - - - - - "no file specfied"', user=user) + test_line('w - - - - - "no file specified"', user=user) + test_line('C - - - - - "no file specified"', user=user) test_line('C non/absolute/path - - - - -', user=user) test_line('b - - - - - -', user=user) test_line('b 1234 - - - - -', user=user) diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index 96d92279fb..0e563f5497 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -75,12 +75,45 @@ static void test_getttyname_malloc(void) { assert_se(PATH_IN_SET(ttyname, "ptmx", "pts/ptmx")); } +static void test_one_color(const char *name, const char *color) { + printf("<%s%s%s>\n", color, name, ansi_normal()); +} + +static void test_colors(void) { + log_info("/* %s */", __func__); + + test_one_color("normal", ansi_normal()); + test_one_color("highlight", ansi_highlight()); + test_one_color("red", ansi_red()); + test_one_color("green", ansi_green()); + test_one_color("yellow", ansi_yellow()); + test_one_color("blue", ansi_blue()); + test_one_color("megenta", ansi_magenta()); + test_one_color("grey", ansi_grey()); + test_one_color("highlight-red", ansi_highlight_red()); + test_one_color("highlight-green", ansi_highlight_green()); + test_one_color("highlight-yellow", ansi_highlight_yellow()); + test_one_color("highlight-blue", ansi_highlight_blue()); + test_one_color("highlight-magenta", ansi_highlight_magenta()); + test_one_color("highlight-grey", ansi_highlight_grey()); + + test_one_color("underline", ansi_underline()); + test_one_color("highlight-underline", ansi_highlight_underline()); + test_one_color("highlight-red-underline", ansi_highlight_red_underline()); + test_one_color("highlight-green-underline", ansi_highlight_green_underline()); + test_one_color("highlight-yellow-underline", ansi_highlight_yellow_underline()); + test_one_color("highlight-blue-underline", ansi_highlight_blue_underline()); + test_one_color("highlight-magenta-underline", ansi_highlight_magenta_underline()); + test_one_color("highlight-grey-underline", ansi_highlight_grey_underline()); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); test_default_term_for_tty(); test_read_one_char(); test_getttyname_malloc(); + test_colors(); return 0; } diff --git a/src/test/test-udev.c b/src/test/test-udev.c index ab31f5a2f1..af43597596 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -22,7 +22,7 @@ #include "signal-util.h" #include "string-util.h" #include "tests.h" -#include "udev.h" +#include "udev-event.h" static int fake_filesystems(void) { static const struct fakefs { diff --git a/src/test/test-umask-util.c b/src/test/test-umask-util.c new file mode 100644 index 0000000000..27f6b56541 --- /dev/null +++ b/src/test/test-umask-util.c @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "tests.h" +#include "umask-util.h" + +int main(int argc, char *argv[]) { + size_t n; + mode_t u; + + test_setup_logging(LOG_DEBUG); + + u = umask(0111); + + n = 0; + RUN_WITH_UMASK(0123) { + assert_se(umask(000) == 0123); + n++; + } + + assert_se(n == 1); + assert_se(umask(u) == 0111); + + RUN_WITH_UMASK(0135) { + assert_se(umask(000) == 0135); + n++; + } + + assert_se(n == 2); + assert_se(umask(0111) == u); + + RUN_WITH_UMASK(0315) { + assert_se(umask(000) == 0315); + n++; + break; + } + + assert_se(n == 3); + assert_se(umask(u) == 0111); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 8a0251e13a..8bc5bf6038 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -1,931 +1,85 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -#include <fcntl.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include <sys/capability.h> -#include <unistd.h> - -#include "all-units.h" -#include "alloc-util.h" -#include "capability-util.h" -#include "conf-parser.h" -#include "env-file.h" -#include "fd-util.h" -#include "format-util.h" -#include "fs-util.h" -#include "hashmap.h" -#include "hostname-util.h" -#include "install-printf.h" -#include "install.h" -#include "load-fragment.h" -#include "macro.h" -#include "memory-util.h" -#include "rm-rf.h" -#include "specifier.h" -#include "string-util.h" +#include "path-lookup.h" +#include "set.h" #include "strv.h" -#include "test-helper.h" #include "tests.h" -#include "tmpfile-util.h" -#include "user-util.h" - -static int test_unit_file_get_set(void) { - int r; - Hashmap *h; +#include "unit-file.h" + +static void test_unit_validate_alias_symlink_and_warn(void) { + log_info("/* %s */", __func__); + + assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.service") == 0); + assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.socket") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.foobar") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.service") == 0); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.socket") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@YYY.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@XXX.service") == 0); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@.service") == 0); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b@.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_and_warn("/path/a@.slice", "/other/b.slice") == -EINVAL); + assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL); +} + +static void test_unit_file_build_name_map(char **ids) { + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + _cleanup_hashmap_free_ Hashmap *unit_ids = NULL; + _cleanup_hashmap_free_ Hashmap *unit_names = NULL; Iterator i; - UnitFileList *p; - - h = hashmap_new(&string_hash_ops); - assert_se(h); - - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); - if (IN_SET(r, -EPERM, -EACCES)) - return log_tests_skipped_errno(r, "unit_file_get_list"); - - log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r, - "unit_file_get_list: %m"); - if (r < 0) - return EXIT_FAILURE; - - HASHMAP_FOREACH(p, h, i) - printf("%s = %s\n", p->path, unit_file_state_to_string(p->state)); - - unit_file_list_free(h); - - return 0; -} - -static void check_execcommand(ExecCommand *c, - const char* path, - const char* argv0, - const char* argv1, - const char* argv2, - bool ignore) { - size_t n; - - assert_se(c); - log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]", - path, argv0 ?: path, argv1, argv2); - n = strv_length(c->argv); - log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]", - c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL); - assert_se(streq(c->path, path)); - assert_se(streq(c->argv[0], argv0 ?: path)); - if (n > 0) - assert_se(streq_ptr(c->argv[1], argv1)); - if (n > 1) - assert_se(streq_ptr(c->argv[2], argv2)); - assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore); -} - -static void test_config_parse_exec(void) { - /* int config_parse_exec( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) */ + const char *k, *dst; + char **v; + usec_t mtime = 0; int r; - ExecCommand *c = NULL, *c1; - const char *ccc; - _cleanup_(manager_freep) Manager *m = NULL; - _cleanup_(unit_freep) Unit *u = NULL; - - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return; - } - - assert_se(r >= 0); - assert_se(manager_startup(m, NULL, NULL) >= 0); - - assert_se(u = unit_new(m, sizeof(Service))); - - log_info("/* basic test */"); - r = config_parse_exec(NULL, "fake", 1, "section", 1, - "LValue", 0, "/RValue r1", - &c, u); - assert_se(r >= 0); - check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false); - - r = config_parse_exec(NULL, "fake", 2, "section", 1, - "LValue", 0, "/RValue///slashes r1///", - &c, u); - - log_info("/* test slashes */"); - assert_se(r >= 0); - c1 = c->command_next; - check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false); - - log_info("/* trailing slash */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "/RValue/ argv0 r1", - &c, u); - assert_se(r == -ENOEXEC); - assert_se(c1->command_next == NULL); - - log_info("/* honour_argv0 */"); - r = config_parse_exec(NULL, "fake", 3, "section", 1, - "LValue", 0, "@/RValue///slashes2 ///argv0 r1", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false); - - log_info("/* honour_argv0, no args */"); - r = config_parse_exec(NULL, "fake", 3, "section", 1, - "LValue", 0, "@/RValue", - &c, u); - assert_se(r == -ENOEXEC); - assert_se(c1->command_next == NULL); - - log_info("/* no command, whitespace only, reset */"); - r = config_parse_exec(NULL, "fake", 3, "section", 1, - "LValue", 0, " ", - &c, u); - assert_se(r == 0); - assert_se(c == NULL); - - log_info("/* ignore && honour_argv0 */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "-@/RValue///slashes3 argv0a r1", - &c, u); - assert_se(r >= 0); - c1 = c; - check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true); - - log_info("/* ignore && honour_argv0 */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "@-/RValue///slashes4 argv0b r1", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true); - - log_info("/* ignore && ignore */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "--/RValue argv0 r1", - &c, u); - assert_se(r == 0); - assert_se(c1->command_next == NULL); - - log_info("/* ignore && ignore (2) */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "-@-/RValue argv0 r1", - &c, u); - assert_se(r == 0); - assert_se(c1->command_next == NULL); - - log_info("/* semicolon */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "-@/RValue argv0 r1 ; " - "/goo/goo boo", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); - - c1 = c1->command_next; - check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false); - - log_info("/* two semicolons in a row */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "-@/RValue argv0 r1 ; ; " - "/goo/goo boo", - &c, u); - assert_se(r == -ENOEXEC); - c1 = c1->command_next; - check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); - - /* second command fails because the executable name is ";" */ - assert_se(c1->command_next == NULL); - - log_info("/* trailing semicolon */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "-@/RValue argv0 r1 ; ", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); - - assert_se(c1->command_next == NULL); - - log_info("/* trailing semicolon, no whitespace */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "-@/RValue argv0 r1 ;", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); - - assert_se(c1->command_next == NULL); - - log_info("/* trailing semicolon in single quotes */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "-@/RValue argv0 r1 ';'", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/RValue", "argv0", "r1", ";", true); - - log_info("/* escaped semicolon */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/bin/find \\;", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); - - log_info("/* escaped semicolon with following arg */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/sbin/find \\; /x", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/sbin/find", NULL, ";", "/x", false); - - log_info("/* escaped semicolon as part of an expression */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/sbin/find \\;x", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/sbin/find", NULL, "\\;x", NULL, false); + assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0); - log_info("/* encoded semicolon */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/bin/find \\073", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + assert_se(unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL) == 1); - log_info("/* quoted semicolon */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/bin/find \";\"", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + HASHMAP_FOREACH_KEY(dst, k, unit_ids, i) + log_info("ids: %s → %s", k, dst); - log_info("/* quoted semicolon with following arg */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/sbin/find \";\" /x", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/sbin/find", NULL, ";", "/x", false); - - log_info("/* spaces in the filename */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "\"/PATH WITH SPACES/daemon\" -1 -2", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false); - - log_info("/* spaces in the filename, no args */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "\"/PATH WITH SPACES/daemon -1 -2\"", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false); - - log_info("/* spaces in the filename, everything quoted */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false); - - log_info("/* escaped spaces in the filename */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false); - - log_info("/* escaped spaces in the filename (2) */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, - "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false); - - for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) { - /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */ - char path[] = "/path\\X"; - path[sizeof(path) - 2] = *ccc; - - log_info("/* invalid character: \\%c */", *ccc); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, path, - &c, u); - assert_se(r == -ENOEXEC); - assert_se(c1->command_next == NULL); + HASHMAP_FOREACH_KEY(v, k, unit_names, i) { + _cleanup_free_ char *j = strv_join(v, ", "); + log_info("aliases: %s ← %s", k, j); } - log_info("/* valid character: \\s */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "/path\\s", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/path ", NULL, NULL, NULL, false); - - log_info("/* quoted backslashes */"); - r = config_parse_exec(NULL, "fake", 5, "section", 1, - "LValue", 0, - "/bin/grep '\\w+\\K'", - &c, u); - assert_se(r >= 0); - c1 = c1->command_next; - check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false); - - log_info("/* trailing backslash: \\ */"); - /* backslash is invalid */ - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "/path\\", - &c, u); - assert_se(r == -ENOEXEC); - assert_se(c1->command_next == NULL); - - log_info("/* missing ending ' */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "/path 'foo", - &c, u); - assert_se(r == -ENOEXEC); - assert_se(c1->command_next == NULL); - - log_info("/* missing ending ' with trailing backslash */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "/path 'foo\\", - &c, u); - assert_se(r == -ENOEXEC); - assert_se(c1->command_next == NULL); - - log_info("/* invalid space between modifiers */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "- /path", - &c, u); - assert_se(r == 0); - assert_se(c1->command_next == NULL); - - log_info("/* only modifiers, no path */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "-", - &c, u); - assert_se(r == 0); - assert_se(c1->command_next == NULL); - - log_info("/* empty argument, reset */"); - r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "", - &c, u); - assert_se(r == 0); - assert_se(c == NULL); - - exec_command_free_list(c); -} - -static void test_config_parse_log_extra_fields(void) { - /* int config_parse_log_extra_fields( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) */ - - int r; - - _cleanup_(manager_freep) Manager *m = NULL; - _cleanup_(unit_freep) Unit *u = NULL; - ExecContext c = {}; - - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return; + char buf[FORMAT_TIMESTAMP_MAX]; + log_debug("Last modification time: %s", format_timestamp(buf, sizeof buf, mtime)); + + r = unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL); + assert_se(IN_SET(r, 0, 1)); + if (r == 0) + log_debug("Cache rebuild skipped based on mtime."); + + + char **id; + STRV_FOREACH(id, ids) { + const char *fragment, *name; + Iterator it; + _cleanup_set_free_free_ Set *names = NULL; + log_info("*** %s ***", *id); + r = unit_file_find_fragment(unit_ids, + unit_names, + *id, + &fragment, + &names); + assert(r == 0); + log_info("fragment: %s", fragment); + log_info("names:"); + SET_FOREACH(name, names, it) + log_info(" %s", name); } - - assert_se(r >= 0); - assert_se(manager_startup(m, NULL, NULL) >= 0); - - assert_se(u = unit_new(m, sizeof(Service))); - - log_info("/* %s – basic test */", __func__); - r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1, - "LValue", 0, "FOO=BAR \"QOOF=quux ' ' \"", - &c, u); - assert_se(r >= 0); - assert_se(c.n_log_extra_fields == 2); - assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len)); - assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len)); - - log_info("/* %s – add some */", __func__); - r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1, - "LValue", 0, "FOO2=BAR2 QOOF2=quux ' '", - &c, u); - assert_se(r >= 0); - assert_se(c.n_log_extra_fields == 4); - assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len)); - assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len)); - assert_se(strneq(c.log_extra_fields[2].iov_base, "FOO2=BAR2", c.log_extra_fields[2].iov_len)); - assert_se(strneq(c.log_extra_fields[3].iov_base, "QOOF2=quux", c.log_extra_fields[3].iov_len)); - - exec_context_dump(&c, stdout, " --> "); - - log_info("/* %s – reset */", __func__); - r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1, - "LValue", 0, "", - &c, u); - assert_se(r >= 0); - assert_se(c.n_log_extra_fields == 0); - - exec_context_free_log_extra_fields(&c); - - log_info("/* %s – bye */", __func__); } -#define env_file_1 \ - "a=a\n" \ - "b=b\\\n" \ - "c\n" \ - "d=d\\\n" \ - "e\\\n" \ - "f\n" \ - "g=g\\ \n" \ - "h=h\n" \ - "i=i\\" - -#define env_file_2 \ - "a=a\\\n" - -#define env_file_3 \ - "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \ - "#--nouser-config \\\n" \ - "normal=line" - -#define env_file_4 \ - "# Generated\n" \ - "\n" \ - "HWMON_MODULES=\"coretemp f71882fg\"\n" \ - "\n" \ - "# For compatibility reasons\n" \ - "\n" \ - "MODULE_0=coretemp\n" \ - "MODULE_1=f71882fg" - -#define env_file_5 \ - "a=\n" \ - "b=" - -static void test_load_env_file_1(void) { - _cleanup_strv_free_ char **data = NULL; - int r; - - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; - - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); - assert_se(streq(data[0], "a=a")); - assert_se(streq(data[1], "b=bc")); - assert_se(streq(data[2], "d=def")); - assert_se(streq(data[3], "g=g ")); - assert_se(streq(data[4], "h=h")); - assert_se(streq(data[5], "i=i")); - assert_se(data[6] == NULL); -} - -static void test_load_env_file_2(void) { - _cleanup_strv_free_ char **data = NULL; - int r; - - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; +int main(int argc, char **argv) { + test_setup_logging(LOG_DEBUG); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2)); + test_unit_validate_alias_symlink_and_warn(); + test_unit_file_build_name_map(strv_skip(argv, 1)); - r = load_env_file(NULL, name, &data); - assert_se(r == 0); - assert_se(streq(data[0], "a=a")); - assert_se(data[1] == NULL); -} - -static void test_load_env_file_3(void) { - _cleanup_strv_free_ char **data = NULL; - int r; - - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; - - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); - assert_se(data == NULL); -} - -static void test_load_env_file_4(void) { - _cleanup_strv_free_ char **data = NULL; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; - int r; - - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); - assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); - assert_se(streq(data[1], "MODULE_0=coretemp")); - assert_se(streq(data[2], "MODULE_1=f71882fg")); - assert_se(data[3] == NULL); -} - -static void test_load_env_file_5(void) { - _cleanup_strv_free_ char **data = NULL; - int r; - - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; - - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); - assert_se(streq(data[0], "a=")); - assert_se(streq(data[1], "b=")); - assert_se(data[2] == NULL); -} - -static void test_install_printf(void) { - char name[] = "name.service", - path[] = "/run/systemd/system/name.service"; - UnitFileInstallInfo i = { .name = name, .path = path, }; - UnitFileInstallInfo i2 = { .name= name, .path = path, }; - char name3[] = "name@inst.service", - path3[] = "/run/systemd/system/name.service"; - UnitFileInstallInfo i3 = { .name = name3, .path = path3, }; - UnitFileInstallInfo i4 = { .name = name3, .path = path3, }; - - _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL; - - assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); - assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); - assert_se(host = gethostname_malloc()); - assert_se(group = gid_to_name(getgid())); - assert_se(asprintf(&gid, UID_FMT, getgid()) >= 0); - assert_se(user = uid_to_name(getuid())); - assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); - -#define expect(src, pattern, result) \ - do { \ - _cleanup_free_ char *t = NULL; \ - _cleanup_free_ char \ - *d1 = strdup(i.name), \ - *d2 = strdup(i.path); \ - assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \ - memzero(i.name, strlen(i.name)); \ - memzero(i.path, strlen(i.path)); \ - assert_se(d1 && d2); \ - if (result) { \ - printf("%s\n", t); \ - assert_se(streq(t, result)); \ - } else assert_se(t == NULL); \ - strcpy(i.name, d1); \ - strcpy(i.path, d2); \ - } while (false) - - expect(i, "%n", "name.service"); - expect(i, "%N", "name"); - expect(i, "%p", "name"); - expect(i, "%i", ""); - expect(i, "%j", "name"); - expect(i, "%g", group); - expect(i, "%G", gid); - expect(i, "%u", user); - expect(i, "%U", uid); - - expect(i, "%m", mid); - expect(i, "%b", bid); - expect(i, "%H", host); - - expect(i2, "%g", group); - expect(i2, "%G", gid); - expect(i2, "%u", user); - expect(i2, "%U", uid); - - expect(i3, "%n", "name@inst.service"); - expect(i3, "%N", "name@inst"); - expect(i3, "%p", "name"); - expect(i3, "%g", group); - expect(i3, "%G", gid); - expect(i3, "%u", user); - expect(i3, "%U", uid); - - expect(i3, "%m", mid); - expect(i3, "%b", bid); - expect(i3, "%H", host); - - expect(i4, "%g", group); - expect(i4, "%G", gid); - expect(i4, "%u", user); - expect(i4, "%U", uid); -} - -static uint64_t make_cap(int cap) { - return ((uint64_t) 1ULL << (uint64_t) cap); -} - -static void test_config_parse_capability_set(void) { - /* int config_parse_capability_set( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) */ - int r; - uint64_t capability_bounding_set = 0; - - r = config_parse_capability_set(NULL, "fake", 1, "section", 1, - "CapabilityBoundingSet", 0, "CAP_NET_RAW", - &capability_bounding_set, NULL); - assert_se(r >= 0); - assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); - - r = config_parse_capability_set(NULL, "fake", 1, "section", 1, - "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", - &capability_bounding_set, NULL); - assert_se(r >= 0); - assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); - - r = config_parse_capability_set(NULL, "fake", 1, "section", 1, - "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN", - &capability_bounding_set, NULL); - assert_se(r >= 0); - assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); - - r = config_parse_capability_set(NULL, "fake", 1, "section", 1, - "CapabilityBoundingSet", 0, "", - &capability_bounding_set, NULL); - assert_se(r >= 0); - assert_se(capability_bounding_set == UINT64_C(0)); - - r = config_parse_capability_set(NULL, "fake", 1, "section", 1, - "CapabilityBoundingSet", 0, "~", - &capability_bounding_set, NULL); - assert_se(r >= 0); - assert_se(cap_test_all(capability_bounding_set)); - - capability_bounding_set = 0; - r = config_parse_capability_set(NULL, "fake", 1, "section", 1, - "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", - &capability_bounding_set, NULL); - assert_se(r >= 0); - assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); -} - -static void test_config_parse_rlimit(void) { - struct rlimit * rl[_RLIMIT_MAX] = {}; - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); - assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); - - rl[RLIMIT_NOFILE]->rlim_cur = 10; - rl[RLIMIT_NOFILE]->rlim_max = 20; - - /* Invalid values don't change rl */ - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); - assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); - assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); - assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0); - assert_se(rl[RLIMIT_NOFILE]); - assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); - assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); - - rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); - assert_se(rl[RLIMIT_CPU]); - assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); - assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); - assert_se(rl[RLIMIT_CPU]); - assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); - assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0); - assert_se(rl[RLIMIT_CPU]); - assert_se(rl[RLIMIT_CPU]->rlim_cur == 40); - assert_se(rl[RLIMIT_CPU]->rlim_max == 60); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); - assert_se(rl[RLIMIT_CPU]); - assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); - assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); - assert_se(rl[RLIMIT_CPU]); - assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); - assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); - - rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); - assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); - assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); - - assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); - assert_se(rl[RLIMIT_RTTIME]); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); - assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); - - rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]); -} - -static void test_config_parse_pass_environ(void) { - /* int config_parse_pass_environ( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) */ - int r; - _cleanup_strv_free_ char **passenv = NULL; - - r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, - "PassEnvironment", 0, "A B", - &passenv, NULL); - assert_se(r >= 0); - assert_se(strv_length(passenv) == 2); - assert_se(streq(passenv[0], "A")); - assert_se(streq(passenv[1], "B")); - - r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, - "PassEnvironment", 0, "", - &passenv, NULL); - assert_se(r >= 0); - assert_se(strv_isempty(passenv)); - - r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, - "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\", - &passenv, NULL); - assert_se(r >= 0); - assert_se(strv_length(passenv) == 1); - assert_se(streq(passenv[0], "normal_name")); - -} - -static void test_unit_dump_config_items(void) { - unit_dump_config_items(stdout); -} - -int main(int argc, char *argv[]) { - _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; - int r; - - test_setup_logging(LOG_INFO); - - r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) - return log_tests_skipped("cgroupfs not available"); - - assert_se(runtime_dir = setup_fake_runtime_dir()); - - r = test_unit_file_get_set(); - test_config_parse_exec(); - test_config_parse_log_extra_fields(); - test_config_parse_capability_set(); - test_config_parse_rlimit(); - test_config_parse_pass_environ(); - test_load_env_file_1(); - test_load_env_file_2(); - test_load_env_file_3(); - test_load_env_file_4(); - test_load_env_file_5(); - TEST_REQ_RUNNING_SYSTEMD(test_install_printf()); - test_unit_dump_config_items(); - - return r; + return 0; } diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 8b230bb290..4d1e49b675 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -50,6 +50,9 @@ static void test_unit_name_is_valid(void) { assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE)); assert_se( unit_name_is_valid("foo@.service", UNIT_NAME_TEMPLATE)); assert_se( unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)); + assert_se( unit_name_is_valid(".test.service", UNIT_NAME_PLAIN)); + assert_se( unit_name_is_valid(".test@.service", UNIT_NAME_TEMPLATE)); + assert_se( unit_name_is_valid("_strange::::.service", UNIT_NAME_ANY)); assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY)); assert_se(!unit_name_is_valid("", UNIT_NAME_ANY)); @@ -430,29 +433,31 @@ static void test_unit_name_to_instance(void) { int r; r = unit_name_to_instance("foo@bar.service", &instance); - assert_se(r >= 0); + assert_se(r == UNIT_NAME_INSTANCE); assert_se(streq(instance, "bar")); free(instance); r = unit_name_to_instance("foo@.service", &instance); - assert_se(r >= 0); + assert_se(r == UNIT_NAME_TEMPLATE); assert_se(streq(instance, "")); free(instance); r = unit_name_to_instance("fo0-stUff_b@b.service", &instance); - assert_se(r >= 0); + assert_se(r == UNIT_NAME_INSTANCE); assert_se(streq(instance, "b")); free(instance); r = unit_name_to_instance("foo.service", &instance); - assert_se(r == 0); + assert_se(r == UNIT_NAME_PLAIN); assert_se(!instance); r = unit_name_to_instance("fooj@unk", &instance); assert_se(r < 0); + assert_se(!instance); r = unit_name_to_instance("foo@", &instance); assert_se(r < 0); + assert_se(!instance); } static void test_unit_name_escape(void) { diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index 1a507bc00a..9475b99c28 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -61,6 +61,43 @@ static void test_uid_ptr(void) { assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); } +static void test_valid_user_group_name_compat(void) { + log_info("/* %s */", __func__); + + assert_se(!valid_user_group_name_compat(NULL)); + assert_se(!valid_user_group_name_compat("")); + assert_se(!valid_user_group_name_compat("1")); + assert_se(!valid_user_group_name_compat("65535")); + assert_se(!valid_user_group_name_compat("-1")); + assert_se(!valid_user_group_name_compat("-kkk")); + assert_se(!valid_user_group_name_compat("rööt")); + assert_se(!valid_user_group_name_compat(".")); + assert_se(!valid_user_group_name_compat(".eff")); + assert_se(!valid_user_group_name_compat("foo\nbar")); + assert_se(!valid_user_group_name_compat("0123456789012345678901234567890123456789")); + assert_se(!valid_user_group_name_or_id_compat("aaa:bbb")); + assert_se(!valid_user_group_name_compat(".")); + assert_se(!valid_user_group_name_compat(".1")); + assert_se(!valid_user_group_name_compat(".65535")); + assert_se(!valid_user_group_name_compat(".-1")); + assert_se(!valid_user_group_name_compat(".-kkk")); + assert_se(!valid_user_group_name_compat(".rööt")); + assert_se(!valid_user_group_name_or_id_compat(".aaa:bbb")); + + assert_se(valid_user_group_name_compat("root")); + assert_se(valid_user_group_name_compat("lennart")); + assert_se(valid_user_group_name_compat("LENNART")); + assert_se(valid_user_group_name_compat("_kkk")); + assert_se(valid_user_group_name_compat("kkk-")); + assert_se(valid_user_group_name_compat("kk-k")); + assert_se(valid_user_group_name_compat("eff.eff")); + assert_se(valid_user_group_name_compat("eff.")); + + assert_se(valid_user_group_name_compat("some5")); + assert_se(!valid_user_group_name_compat("5some")); + assert_se(valid_user_group_name_compat("INNER5NUMBER")); +} + static void test_valid_user_group_name(void) { log_info("/* %s */", __func__); @@ -72,10 +109,17 @@ static void test_valid_user_group_name(void) { assert_se(!valid_user_group_name("-kkk")); assert_se(!valid_user_group_name("rööt")); assert_se(!valid_user_group_name(".")); - assert_se(!valid_user_group_name("eff.eff")); + assert_se(!valid_user_group_name(".eff")); assert_se(!valid_user_group_name("foo\nbar")); assert_se(!valid_user_group_name("0123456789012345678901234567890123456789")); assert_se(!valid_user_group_name_or_id("aaa:bbb")); + assert_se(!valid_user_group_name(".")); + assert_se(!valid_user_group_name(".1")); + assert_se(!valid_user_group_name(".65535")); + assert_se(!valid_user_group_name(".-1")); + assert_se(!valid_user_group_name(".-kkk")); + assert_se(!valid_user_group_name(".rööt")); + assert_se(!valid_user_group_name_or_id(".aaa:bbb")); assert_se(valid_user_group_name("root")); assert_se(valid_user_group_name("lennart")); @@ -83,12 +127,47 @@ static void test_valid_user_group_name(void) { assert_se(valid_user_group_name("_kkk")); assert_se(valid_user_group_name("kkk-")); assert_se(valid_user_group_name("kk-k")); + assert_se(!valid_user_group_name("eff.eff")); + assert_se(!valid_user_group_name("eff.")); assert_se(valid_user_group_name("some5")); assert_se(!valid_user_group_name("5some")); assert_se(valid_user_group_name("INNER5NUMBER")); } +static void test_valid_user_group_name_or_id_compat(void) { + log_info("/* %s */", __func__); + + assert_se(!valid_user_group_name_or_id_compat(NULL)); + assert_se(!valid_user_group_name_or_id_compat("")); + assert_se(valid_user_group_name_or_id_compat("0")); + assert_se(valid_user_group_name_or_id_compat("1")); + assert_se(valid_user_group_name_or_id_compat("65534")); + assert_se(!valid_user_group_name_or_id_compat("65535")); + assert_se(valid_user_group_name_or_id_compat("65536")); + assert_se(!valid_user_group_name_or_id_compat("-1")); + assert_se(!valid_user_group_name_or_id_compat("-kkk")); + assert_se(!valid_user_group_name_or_id_compat("rööt")); + assert_se(!valid_user_group_name_or_id_compat(".")); + assert_se(!valid_user_group_name_or_id_compat(".eff")); + assert_se(valid_user_group_name_or_id_compat("eff.eff")); + assert_se(valid_user_group_name_or_id_compat("eff.")); + assert_se(!valid_user_group_name_or_id_compat("foo\nbar")); + assert_se(!valid_user_group_name_or_id_compat("0123456789012345678901234567890123456789")); + assert_se(!valid_user_group_name_or_id_compat("aaa:bbb")); + + assert_se(valid_user_group_name_or_id_compat("root")); + assert_se(valid_user_group_name_or_id_compat("lennart")); + assert_se(valid_user_group_name_or_id_compat("LENNART")); + assert_se(valid_user_group_name_or_id_compat("_kkk")); + assert_se(valid_user_group_name_or_id_compat("kkk-")); + assert_se(valid_user_group_name_or_id_compat("kk-k")); + + assert_se(valid_user_group_name_or_id_compat("some5")); + assert_se(!valid_user_group_name_or_id_compat("5some")); + assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER")); +} + static void test_valid_user_group_name_or_id(void) { log_info("/* %s */", __func__); @@ -103,7 +182,9 @@ static void test_valid_user_group_name_or_id(void) { assert_se(!valid_user_group_name_or_id("-kkk")); assert_se(!valid_user_group_name_or_id("rööt")); assert_se(!valid_user_group_name_or_id(".")); + assert_se(!valid_user_group_name_or_id(".eff")); assert_se(!valid_user_group_name_or_id("eff.eff")); + assert_se(!valid_user_group_name_or_id("eff.")); assert_se(!valid_user_group_name_or_id("foo\nbar")); assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789")); assert_se(!valid_user_group_name_or_id("aaa:bbb")); @@ -191,6 +272,20 @@ static void test_get_group_creds_one(const char *id, const char *name, gid_t gid assert_se(rgid == gid); } +static void test_make_salt(void) { + log_info("/* %s */", __func__); + + _cleanup_free_ char *s, *t; + + assert_se(make_salt(&s) == 0); + log_info("got %s", s); + + assert_se(make_salt(&t) == 0); + log_info("got %s", t); + + assert(!streq(s, t)); +} + int main(int argc, char *argv[]) { test_uid_to_name_one(0, "root"); test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME); @@ -205,8 +300,8 @@ int main(int argc, char *argv[]) { test_get_user_creds_one("root", "root", 0, 0, "/root", "/bin/sh"); test_get_user_creds_one("0", "root", 0, 0, "/root", "/bin/sh"); - test_get_user_creds_one(NOBODY_USER_NAME, NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", "/sbin/nologin"); - test_get_user_creds_one("65534", NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", "/sbin/nologin"); + test_get_user_creds_one(NOBODY_USER_NAME, NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN); + test_get_user_creds_one("65534", NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN); test_get_group_creds_one("root", "root", 0); test_get_group_creds_one("0", "root", 0); @@ -216,10 +311,14 @@ int main(int argc, char *argv[]) { test_parse_uid(); test_uid_ptr(); + test_valid_user_group_name_compat(); test_valid_user_group_name(); + test_valid_user_group_name_or_id_compat(); test_valid_user_group_name_or_id(); test_valid_gecos(); test_valid_home(); + test_make_salt(); + return 0; } diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index d1e48da2a6..b5c4e3dc34 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -7,6 +7,8 @@ #include "util.h" static void test_utf8_is_printable(void) { + log_info("/* %s */", __func__); + assert_se(utf8_is_printable("ascii is valid\tunicode", 22)); assert_se(utf8_is_printable("\342\204\242", 3)); assert_se(!utf8_is_printable("\341\204", 2)); @@ -14,18 +16,24 @@ static void test_utf8_is_printable(void) { } static void test_utf8_is_valid(void) { + log_info("/* %s */", __func__); + assert_se(utf8_is_valid("ascii is valid unicode")); assert_se(utf8_is_valid("\342\204\242")); assert_se(!utf8_is_valid("\341\204")); } static void test_ascii_is_valid(void) { + log_info("/* %s */", __func__); + assert_se( ascii_is_valid("alsdjf\t\vbarr\nba z")); assert_se(!ascii_is_valid("\342\204\242")); assert_se(!ascii_is_valid("\341\204")); } static void test_ascii_is_valid_n(void) { + log_info("/* %s */", __func__); + assert_se( ascii_is_valid_n("alsdjf\t\vbarr\nba z", 17)); assert_se( ascii_is_valid_n("alsdjf\t\vbarr\nba z", 16)); assert_se(!ascii_is_valid_n("alsdjf\t\vbarr\nba z", 18)); @@ -36,6 +44,8 @@ static void test_ascii_is_valid_n(void) { } static void test_utf8_encoded_valid_unichar(void) { + log_info("/* %s */", __func__); + assert_se(utf8_encoded_valid_unichar("\342\204\242", 1) == -EINVAL); /* truncated */ assert_se(utf8_encoded_valid_unichar("\342\204\242", 2) == -EINVAL); /* truncated */ assert_se(utf8_encoded_valid_unichar("\342\204\242", 3) == 3); @@ -53,9 +63,11 @@ static void test_utf8_encoded_valid_unichar(void) { assert_se(utf8_encoded_valid_unichar("\341\204\341\204", 5) == -EINVAL); } -static void test_utf8_escaping(void) { +static void test_utf8_escape_invalid(void) { _cleanup_free_ char *p1, *p2, *p3; + log_info("/* %s */", __func__); + p1 = utf8_escape_invalid("goo goo goo"); puts(p1); assert_se(utf8_is_valid(p1)); @@ -69,9 +81,11 @@ static void test_utf8_escaping(void) { assert_se(utf8_is_valid(p3)); } -static void test_utf8_escaping_printable(void) { +static void test_utf8_escape_non_printable(void) { _cleanup_free_ char *p1, *p2, *p3, *p4, *p5, *p6; + log_info("/* %s */", __func__); + p1 = utf8_escape_non_printable("goo goo goo"); puts(p1); assert_se(utf8_is_valid(p1)); @@ -97,12 +111,45 @@ static void test_utf8_escaping_printable(void) { assert_se(utf8_is_valid(p6)); } +static void test_utf8_escape_non_printable_full(void) { + log_info("/* %s */", __func__); + + for (size_t i = 0; i < 20; i++) { + _cleanup_free_ char *p; + + p = utf8_escape_non_printable_full("goo goo goo", i); + puts(p); + assert_se(utf8_is_valid(p)); + assert_se(utf8_console_width(p) <= i); + } + + for (size_t i = 0; i < 20; i++) { + _cleanup_free_ char *p; + + p = utf8_escape_non_printable_full("\001 \019\20\a", i); + puts(p); + assert_se(utf8_is_valid(p)); + assert_se(utf8_console_width(p) <= i); + } + + for (size_t i = 0; i < 20; i++) { + _cleanup_free_ char *p; + + p = utf8_escape_non_printable_full("\xef\xbf\x30\x13", i); + puts(p); + assert_se(utf8_is_valid(p)); + assert_se(utf8_console_width(p) <= i); + } +} + static void test_utf16_to_utf8(void) { const char16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) }; static const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7 }; _cleanup_free_ char16_t *b = NULL; _cleanup_free_ char *a = NULL; + log_info("/* %s */", __func__); + /* Convert UTF-16 to UTF-8, filtering embedded bad chars */ a = utf16_to_utf8(utf16, sizeof(utf16)); assert_se(a); @@ -120,6 +167,8 @@ static void test_utf16_to_utf8(void) { } static void test_utf8_n_codepoints(void) { + log_info("/* %s */", __func__); + assert_se(utf8_n_codepoints("abc") == 3); assert_se(utf8_n_codepoints("zażółcić gęślą jaźń") == 19); assert_se(utf8_n_codepoints("串") == 1); @@ -129,6 +178,8 @@ static void test_utf8_n_codepoints(void) { } static void test_utf8_console_width(void) { + log_info("/* %s */", __func__); + assert_se(utf8_console_width("abc") == 3); assert_se(utf8_console_width("zażółcić gęślą jaźń") == 19); assert_se(utf8_console_width("串") == 2); @@ -140,6 +191,8 @@ static void test_utf8_console_width(void) { static void test_utf8_to_utf16(void) { const char *p; + log_info("/* %s */", __func__); + FOREACH_STRING(p, "abc", "zażółcić gęślą jaźń", @@ -165,8 +218,9 @@ int main(int argc, char *argv[]) { test_ascii_is_valid(); test_ascii_is_valid_n(); test_utf8_encoded_valid_unichar(); - test_utf8_escaping(); - test_utf8_escaping_printable(); + test_utf8_escape_invalid(); + test_utf8_escape_non_printable(); + test_utf8_escape_non_printable_full(); test_utf16_to_utf8(); test_utf8_n_codepoints(); test_utf8_console_width(); diff --git a/src/test/test-varlink.c b/src/test/test-varlink.c new file mode 100644 index 0000000000..fbfc72cd81 --- /dev/null +++ b/src/test/test-varlink.c @@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <fcntl.h> +#include <poll.h> +#include <pthread.h> + +#include "sd-event.h" + +#include "fd-util.h" +#include "json.h" +#include "rm-rf.h" +#include "strv.h" +#include "tmpfile-util.h" +#include "user-util.h" +#include "varlink.h" + +/* Let's pick some high value, that is higher than the largest listen() backlog, but leaves enough room below + the typical RLIMIT_NOFILE value of 1024 so that we can process both sides of each socket in our + process. Or in other words: "OVERLOAD_CONNECTIONS * 2 + x < 1024" should hold, for some small x that + should cover any auxiliary fds, the listener server fds, stdin/stdout/stderr and whatever else. */ +#define OVERLOAD_CONNECTIONS 333 + +static int n_done = 0; +static int block_write_fd = -1; + +static int method_something(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { + _cleanup_(json_variant_unrefp) JsonVariant *ret = NULL; + JsonVariant *a, *b; + intmax_t x, y; + int r; + + a = json_variant_by_key(parameters, "a"); + if (!a) + return varlink_error(link, "io.test.BadParameters", NULL); + + x = json_variant_integer(a); + + b = json_variant_by_key(parameters, "b"); + if (!b) + return varlink_error(link, "io.test.BadParameters", NULL); + + y = json_variant_integer(b); + + r = json_build(&ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("sum", JSON_BUILD_INTEGER(x + y)))); + if (r < 0) + return r; + + return varlink_reply(link, ret); +} + +static int method_done(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { + + if (++n_done == 2) + sd_event_exit(varlink_get_event(link), EXIT_FAILURE); + + return 0; +} + +static int reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) { + JsonVariant *sum; + + sum = json_variant_by_key(parameters, "sum"); + + assert_se(json_variant_integer(sum) == 7+22); + + if (++n_done == 2) + sd_event_exit(varlink_get_event(link), EXIT_FAILURE); + + return 0; +} + +static int on_connect(VarlinkServer *s, Varlink *link, void *userdata) { + uid_t uid = UID_INVALID; + + assert(s); + assert(link); + + assert_se(varlink_get_peer_uid(link, &uid) >= 0); + assert_se(getuid() == uid); + + return 0; +} + +static int overload_reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) { + + /* This method call reply should always be called with a disconnection, since the method call should + * be talking to an overloaded server */ + + log_debug("Over reply triggered with error: %s", strna(error_id)); + assert_se(streq(error_id, VARLINK_ERROR_DISCONNECTED)); + sd_event_exit(varlink_get_event(link), 0); + + return 0; +} + +static void flood_test(const char *address) { + _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_free_ Varlink **connections = NULL; + size_t k; + char x = 'x'; + + log_debug("Flooding server..."); + + /* Block the main event loop while we flood */ + assert_se(write(block_write_fd, &x, sizeof(x)) == sizeof(x)); + + assert_se(sd_event_default(&e) >= 0); + + /* Flood the server with connections */ + assert_se(connections = new0(Varlink*, OVERLOAD_CONNECTIONS)); + for (k = 0; k < OVERLOAD_CONNECTIONS; k++) { + _cleanup_free_ char *t = NULL; + log_debug("connection %zu", k); + assert_se(varlink_connect_address(connections + k, address) >= 0); + + assert_se(asprintf(&t, "flood-%zu", k) >= 0); + assert_se(varlink_set_description(connections[k], t) >= 0); + assert_se(varlink_attach_event(connections[k], e, k) >= 0); + assert_se(varlink_sendb(connections[k], "io.test.Rubbish", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("id", JSON_BUILD_INTEGER(k)))) >= 0); + } + + /* Then, create one more, which should fail */ + log_debug("Creating overload connection..."); + assert_se(varlink_connect_address(&c, address) >= 0); + assert_se(varlink_set_description(c, "overload-client") >= 0); + assert_se(varlink_attach_event(c, e, k) >= 0); + assert_se(varlink_bind_reply(c, overload_reply) >= 0); + assert_se(varlink_invokeb(c, "io.test.Overload", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("foo", JSON_BUILD_STRING("bar")))) >= 0); + + /* Unblock it */ + log_debug("Unblocking server..."); + block_write_fd = safe_close(block_write_fd); + + /* This loop will terminate as soon as the overload reply callback is called */ + assert_se(sd_event_loop(e) >= 0); + + /* And close all connections again */ + for (k = 0; k < OVERLOAD_CONNECTIONS; k++) + connections[k] = varlink_unref(connections[k]); +} + +static void *thread(void *arg) { + _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *i = NULL; + JsonVariant *o = NULL; + const char *e; + + assert_se(json_build(&i, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_INTEGER(88)), + JSON_BUILD_PAIR("b", JSON_BUILD_INTEGER(99)))) >= 0); + + assert_se(varlink_connect_address(&c, arg) >= 0); + assert_se(varlink_set_description(c, "thread-client") >= 0); + + assert_se(varlink_call(c, "io.test.DoSomething", i, &o, &e, NULL) >= 0); + assert_se(json_variant_integer(json_variant_by_key(o, "sum")) == 88 + 99); + assert_se(!e); + + assert_se(varlink_callb(c, "io.test.IDontExist", &o, &e, NULL, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_REAL(5.5)))) >= 0); + assert_se(streq_ptr(json_variant_string(json_variant_by_key(o, "method")), "io.test.IDontExist")); + assert_se(streq(e, VARLINK_ERROR_METHOD_NOT_FOUND)); + + flood_test(arg); + + assert_se(varlink_send(c, "io.test.Done", NULL) >= 0); + + return NULL; +} + +static int block_fd_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + char c; + + assert_se(fd_nonblock(fd, false) >= 0); + + assert_se(read(fd, &c, sizeof(c)) == sizeof(c)); + /* When a character is written to this pipe we'll block until the pipe is closed. */ + + assert_se(read(fd, &c, sizeof(c)) == 0); + + assert_se(fd_nonblock(fd, true) >= 0); + + assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0); + + return 0; +} + +int main(int argc, char *argv[]) { + _cleanup_(sd_event_source_unrefp) sd_event_source *block_event = NULL; + _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL; + _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL; + _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_(close_pairp) int block_fds[2] = { -1, -1 }; + pthread_t t; + const char *sp; + + log_set_max_level(LOG_DEBUG); + log_open(); + + assert_se(mkdtemp_malloc("/tmp/varlink-test-XXXXXX", &tmpdir) >= 0); + sp = strjoina(tmpdir, "/socket"); + + assert_se(sd_event_default(&e) >= 0); + + assert_se(pipe2(block_fds, O_NONBLOCK|O_CLOEXEC) >= 0); + assert_se(sd_event_add_io(e, &block_event, block_fds[0], EPOLLIN, block_fd_handler, NULL) >= 0); + assert_se(sd_event_source_set_priority(block_event, SD_EVENT_PRIORITY_IMPORTANT) >= 0); + block_write_fd = TAKE_FD(block_fds[1]); + + assert_se(varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID) >= 0); + assert_se(varlink_server_set_description(s, "our-server") >= 0); + + assert_se(varlink_server_bind_method(s, "io.test.DoSomething", method_something) >= 0); + assert_se(varlink_server_bind_method(s, "io.test.Done", method_done) >= 0); + assert_se(varlink_server_bind_connect(s, on_connect) >= 0); + assert_se(varlink_server_listen_address(s, sp, 0600) >= 0); + assert_se(varlink_server_attach_event(s, e, 0) >= 0); + assert_se(varlink_server_set_connections_max(s, OVERLOAD_CONNECTIONS) >= 0); + + assert_se(varlink_connect_address(&c, sp) >= 0); + assert_se(varlink_set_description(c, "main-client") >= 0); + assert_se(varlink_bind_reply(c, reply) >= 0); + + assert_se(json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_INTEGER(7)), + JSON_BUILD_PAIR("b", JSON_BUILD_INTEGER(22)))) >= 0); + + assert_se(varlink_invoke(c, "io.test.DoSomething", v) >= 0); + + assert_se(varlink_attach_event(c, e, 0) >= 0); + + assert_se(pthread_create(&t, NULL, thread, (void*) sp) == 0); + + assert_se(sd_event_loop(e) >= 0); + + assert_se(pthread_join(t, NULL) == 0); + + return 0; +} |