summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2014-04-26 10:08:46 +0200
committerMichael Stapelberg <michael@stapelberg.de>2014-04-26 10:08:46 +0200
commit663996b3bb3cdaa81ac830674fdda00e28a2485b (patch)
treeec5ccfae391a7cc7970f7618a58970c87dec770b /src/test
downloadsystemd-663996b3bb3cdaa81ac830674fdda00e28a2485b.tar.gz
Imported Upstream version 204
Diffstat (limited to 'src/test')
-rw-r--r--src/test/test-calendarspec.c88
-rw-r--r--src/test/test-cgroup-util.c183
-rw-r--r--src/test/test-cgroup.c105
-rw-r--r--src/test/test-daemon.c37
-rw-r--r--src/test/test-date.c61
-rw-r--r--src/test/test-efivars.c47
-rw-r--r--src/test/test-engine.c99
-rw-r--r--src/test/test-env-replace.c218
-rw-r--r--src/test/test-fileio.c145
-rw-r--r--src/test/test-hashmap.c508
-rw-r--r--src/test/test-hostname.c38
-rw-r--r--src/test/test-id128.c75
-rw-r--r--src/test/test-install.c265
-rw-r--r--src/test/test-job-type.c105
-rw-r--r--src/test/test-libudev.c520
-rw-r--r--src/test/test-log.c53
-rw-r--r--src/test/test-loopback.c37
-rw-r--r--src/test/test-ns.c73
-rw-r--r--src/test/test-path-util.c89
-rw-r--r--src/test/test-prioq.c166
-rw-r--r--src/test/test-replace-var.c46
-rw-r--r--src/test/test-sched-prio.c92
-rw-r--r--src/test/test-sleep.c57
-rw-r--r--src/test/test-strbuf.c93
-rw-r--r--src/test/test-strip-tab-ansi.c52
-rw-r--r--src/test/test-strv.c265
-rw-r--r--src/test/test-strxcpyx.c101
-rw-r--r--src/test/test-time.c136
-rw-r--r--src/test/test-udev.c171
-rw-r--r--src/test/test-unit-file.c367
-rw-r--r--src/test/test-unit-name.c199
-rw-r--r--src/test/test-util.c472
-rw-r--r--src/test/test-watchdog.c51
33 files changed, 5014 insertions, 0 deletions
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
new file mode 100644
index 0000000000..21b0024388
--- /dev/null
+++ b/src/test/test-calendarspec.c
@@ -0,0 +1,88 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "calendarspec.h"
+#include "util.h"
+
+static void test_one(const char *input, const char *output) {
+ CalendarSpec *c;
+ _cleanup_free_ char *p = NULL, *q = NULL;
+ usec_t u;
+ char buf[FORMAT_TIMESTAMP_MAX];
+ int r;
+
+ assert_se(calendar_spec_from_string(input, &c) >= 0);
+
+ assert_se(calendar_spec_to_string(c, &p) >= 0);
+ printf("\"%s\" → \"%s\"\n", input, p);
+
+ assert_se(streq(p, 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));
+ calendar_spec_free(c);
+
+ assert_se(calendar_spec_from_string(p, &c) >= 0);
+ assert_se(calendar_spec_to_string(c, &q) >= 0);
+ calendar_spec_free(c);
+
+ assert_se(streq(q, p));
+}
+
+int main(int argc, char* argv[]) {
+ CalendarSpec *c;
+
+ test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon-Thu,Sat,Sun *-*-* 00:00:00");
+ test_one("Mon,Sun 12-*-* 2,1:23", "Mon,Sun 2012-*-* 01,02:23:00");
+ test_one("Wed *-1", "Wed *-*-01 00:00:00");
+ test_one("Wed-Wed,Wed *-1", "Wed *-*-01 00:00:00");
+ test_one("Wed, 17:48", "Wed *-*-* 17:48:00");
+ test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue-Sat 2012-10-15 01:02:03");
+ test_one("*-*-7 0:0:0", "*-*-07 00:00:00");
+ test_one("10-15", "*-10-15 00:00:00");
+ test_one("monday *-12-* 17:00", "Mon *-12-* 17:00:00");
+ test_one("Mon,Fri *-*-3,1,2 *:30:45", "Mon,Fri *-*-01,02,03 *:30:45");
+ test_one("12,14,13,12:20,10,30", "*-*-* 12,13,14:10,20,30:00");
+ test_one("mon,fri *-1/2-1,3 *:30:45", "Mon,Fri *-01/2-01,03 *:30:45");
+ test_one("03-05 08:05:40", "*-03-05 08:05:40");
+ test_one("08:05:40", "*-*-* 08:05:40");
+ test_one("05:40", "*-*-* 05:40:00");
+ test_one("Sat,Sun 12-05 08:05:40", "Sat,Sun *-12-05 08:05:40");
+ test_one("Sat,Sun 08:05:40", "Sat,Sun *-*-* 08:05:40");
+ test_one("2003-03-05 05:40", "2003-03-05 05:40:00");
+ test_one("2003-03-05", "2003-03-05 00:00:00");
+ test_one("03-05", "*-03-05 00:00:00");
+ test_one("hourly", "*-*-* *:00:00");
+ test_one("daily", "*-*-* 00:00:00");
+ test_one("monthly", "*-*-01 00:00:00");
+ test_one("weekly", "Mon *-*-* 00:00:00");
+ test_one("*:2/3", "*-*-* *:02/3:00");
+
+ assert_se(calendar_spec_from_string("test", &c) < 0);
+ assert_se(calendar_spec_from_string("", &c) < 0);
+ assert_se(calendar_spec_from_string("7", &c) < 0);
+ assert_se(calendar_spec_from_string("121212:1:2", &c) < 0);
+
+ return 0;
+}
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
new file mode 100644
index 0000000000..c9634d42b0
--- /dev/null
+++ b/src/test/test-cgroup-util.c
@@ -0,0 +1,183 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+
+#include "util.h"
+#include "cgroup-util.h"
+
+static void check_p_d_u(const char *path, int code, const char *result) {
+ _cleanup_free_ char *unit = NULL;
+
+ assert_se(cg_path_decode_unit(path, &unit) == code);
+ assert_se(streq_ptr(unit, result));
+}
+
+static void test_path_decode_unit(void) {
+ check_p_d_u("getty@.service/getty@tty2.service", 0, "getty@tty2.service");
+ check_p_d_u("getty@.service/getty@tty2.service/xxx", 0, "getty@tty2.service");
+ check_p_d_u("getty@.service/", -EINVAL, NULL);
+ check_p_d_u("getty@.service", -EINVAL, NULL);
+ check_p_d_u("getty.service", 0, "getty.service");
+ check_p_d_u("getty", -EINVAL, NULL);
+}
+
+static void check_p_g_u(const char *path, int code, const char *result) {
+ _cleanup_free_ char *unit = NULL;
+
+ assert_se(cg_path_get_unit(path, &unit) == code);
+ assert_se(streq_ptr(unit, result));
+}
+
+static void check_p_g_u_u(const char *path, int code, const char *result) {
+ _cleanup_free_ char *unit = NULL;
+
+ assert_se(cg_path_get_user_unit(path, &unit) == code);
+ assert_se(streq_ptr(unit, result));
+}
+
+static void test_path_get_unit(void) {
+ check_p_g_u("/system/foobar.service/sdfdsaf", 0, "foobar.service");
+ check_p_g_u("/system/getty@.service/getty@tty5.service", 0, "getty@tty5.service");
+ check_p_g_u("/system/getty@.service/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
+ check_p_g_u("/system/getty@.service/getty@tty5.service/", 0, "getty@tty5.service");
+ check_p_g_u("/system/getty@tty6.service/tty5", 0, "getty@tty6.service");
+ check_p_g_u("sadfdsafsda", -ENOENT, NULL);
+ check_p_g_u("/system/getty####@tty6.service/tty5", -EINVAL, NULL);
+}
+
+static void test_path_get_user_unit(void) {
+ check_p_g_u_u("/user/lennart/2/systemd-21548/foobar.service", 0, "foobar.service");
+ check_p_g_u_u("/user/lennart/2/systemd-21548/foobar.service/waldo", 0, "foobar.service");
+ check_p_g_u_u("/user/lennart/2/systemd-21548/foobar.service/waldo/uuuux", 0, "foobar.service");
+ check_p_g_u_u("/user/lennart/2/systemd-21548/waldo/waldo/uuuux", -EINVAL, NULL);
+ check_p_g_u_u("/user/lennart/2/foobar.service", -ENOENT, NULL);
+ check_p_g_u_u("/user/lennart/2/systemd-21548/foobar@.service/foobar@pie.service/pa/po", 0, "foobar@pie.service");
+}
+
+static void test_get_paths(void) {
+ _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL;
+
+ assert_se(cg_get_root_path(&a) >= 0);
+ log_info("Root = %s", a);
+
+ assert_se(cg_get_system_path(&b) >= 0);
+ log_info("System = %s", b);
+
+ assert_se(cg_get_user_path(&c) >= 0);
+ log_info("User = %s", c);
+
+ assert_se(cg_get_machine_path("harley", &d) >= 0);
+ log_info("Machine = %s", d);
+}
+
+static void test_proc(void) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r;
+
+ d = opendir("/proc");
+ assert_se(d);
+
+ FOREACH_DIRENT(de, d, break) {
+ _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *prefix = NULL;
+ pid_t pid;
+ uid_t uid = (uid_t) -1;
+
+ if (de->d_type != DT_DIR &&
+ de->d_type != DT_UNKNOWN)
+ continue;
+
+ r = parse_pid(de->d_name, &pid);
+ if (r < 0)
+ continue;
+
+ if (is_kernel_thread(pid))
+ continue;
+
+ cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
+ cg_pid_get_path_shifted(pid, &prefix, &path_shifted);
+ cg_pid_get_owner_uid(pid, &uid);
+ cg_pid_get_session(pid, &session);
+ cg_pid_get_unit(pid, &unit);
+ cg_pid_get_user_unit(pid, &user_unit);
+ cg_pid_get_machine_name(pid, &machine);
+
+ printf("%lu\t%s\t%s\t%s\t%lu\t%s\t%s\t%s\t%s\n",
+ (unsigned long) pid,
+ path,
+ prefix,
+ path_shifted,
+ (unsigned long) uid,
+ session,
+ unit,
+ user_unit,
+ machine);
+ }
+}
+
+static void test_escape_one(const char *s, const char *r) {
+ _cleanup_free_ char *b;
+
+ b = cg_escape(s);
+ assert_se(b);
+ assert_se(streq(b, r));
+
+ assert_se(streq(cg_unescape(b), s));
+}
+
+static void test_escape(void) {
+ test_escape_one("foobar", "foobar");
+ test_escape_one(".foobar", "_.foobar");
+ test_escape_one("foobar.service", "foobar.service");
+ test_escape_one("cgroup.service", "_cgroup.service");
+ test_escape_one("cpu.service", "_cpu.service");
+ test_escape_one("tasks", "_tasks");
+ test_escape_one("_foobar", "__foobar");
+ test_escape_one("", "_");
+ test_escape_one("_", "__");
+ test_escape_one(".", "_.");
+}
+
+static void test_controller_is_valid(void) {
+ assert_se(cg_controller_is_valid("foobar", false));
+ assert_se(cg_controller_is_valid("foo_bar", false));
+ assert_se(cg_controller_is_valid("name=foo", true));
+ assert_se(!cg_controller_is_valid("", false));
+ assert_se(!cg_controller_is_valid("name=", true));
+ assert_se(!cg_controller_is_valid("=", false));
+ assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
+ assert_se(!cg_controller_is_valid("_", false));
+ assert_se(!cg_controller_is_valid("_foobar", false));
+ assert_se(!cg_controller_is_valid("tatü", false));
+}
+
+int main(void) {
+ test_path_decode_unit();
+ test_path_get_unit();
+ test_path_get_user_unit();
+ test_get_paths();
+ test_proc();
+ test_escape();
+ test_controller_is_valid();
+
+ return 0;
+}
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
new file mode 100644
index 0000000000..3a3489d6a2
--- /dev/null
+++ b/src/test/test-cgroup.c
@@ -0,0 +1,105 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <string.h>
+
+#include "cgroup-util.h"
+#include "path-util.h"
+#include "util.h"
+#include "log.h"
+
+int main(int argc, char*argv[]) {
+ char *path;
+ char *c, *p;
+
+ assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a", NULL) == 0);
+ assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a", NULL) == 0);
+ assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b", NULL) == 0);
+ assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c", NULL) == 0);
+ assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0);
+
+ assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
+ assert_se(streq(path, "/test-b"));
+ free(path);
+
+ assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) == 0);
+
+ assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
+ assert_se(path_equal(path, "/test-a"));
+ free(path);
+
+ assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", 0) == 0);
+
+ assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
+ assert_se(path_equal(path, "/test-b/test-d"));
+ free(path);
+
+ assert_se(cg_get_path(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", NULL, &path) == 0);
+ assert_se(path_equal(path, "/sys/fs/cgroup/systemd/test-b/test-d"));
+ free(path);
+
+ assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0);
+ assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) == 0);
+
+ assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0);
+ assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0);
+
+ assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", false, false) > 0);
+
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) == 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0);
+
+ assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0);
+ assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0);
+
+ cg_trim(SYSTEMD_CGROUP_CONTROLLER, "/", false);
+
+ assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-b") < 0);
+ assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0);
+
+ assert_se(cg_split_spec("foobar:/", &c, &p) == 0);
+ assert(streq(c, "foobar"));
+ assert(streq(p, "/"));
+ free(c);
+ free(p);
+
+ assert_se(cg_split_spec("foobar:", &c, &p) < 0);
+ assert_se(cg_split_spec("foobar:asdfd", &c, &p) < 0);
+ assert_se(cg_split_spec(":///", &c, &p) < 0);
+ assert_se(cg_split_spec(":", &c, &p) < 0);
+ assert_se(cg_split_spec("", &c, &p) < 0);
+ assert_se(cg_split_spec("fo/obar:/", &c, &p) < 0);
+
+ assert_se(cg_split_spec("/", &c, &p) >= 0);
+ assert(c == NULL);
+ assert(streq(p, "/"));
+ free(p);
+
+ assert_se(cg_split_spec("foo", &c, &p) >= 0);
+ assert(streq(c, "foo"));
+ assert(p == NULL);
+ free(c);
+
+ return 0;
+}
diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c
new file mode 100644
index 0000000000..3215f0c560
--- /dev/null
+++ b/src/test/test-daemon.c
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+
+#include <systemd/sd-daemon.h>
+
+int main(int argc, char*argv[]) {
+
+ sd_notify(0, "STATUS=Starting up");
+ sleep(5);
+ sd_notify(0,
+ "STATUS=Running\n"
+ "READY=1");
+ sleep(10);
+ sd_notify(0, "STATUS=Quitting");
+
+ return 0;
+}
diff --git a/src/test/test-date.c b/src/test/test-date.c
new file mode 100644
index 0000000000..40ffc17b2f
--- /dev/null
+++ b/src/test/test-date.c
@@ -0,0 +1,61 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "util.h"
+
+static void test_one(const char *p) {
+ usec_t t, q;
+ char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert_se(parse_timestamp(p, &t) >= 0);
+ log_info("%s", format_timestamp(buf, sizeof(buf), t));
+
+ /* Chop off timezone */
+ *strrchr(buf, ' ') = 0;
+
+ assert_se(parse_timestamp(buf, &q) >= 0);
+ assert_se(q == t);
+
+ log_info("%s", strna(format_timestamp_relative(buf_relative, sizeof(buf_relative), t)));
+ assert_se(parse_timestamp(buf, &q) >= 0);
+}
+
+int main(int argc, char *argv[]) {
+ test_one("17:41");
+ test_one("18:42:44");
+ test_one("12-10-02 12:13:14");
+ test_one("12-10-2 12:13:14");
+ test_one("12-10-03 12:13");
+ test_one("2012-12-30 18:42");
+ test_one("2012-10-02");
+ test_one("Tue 2012-10-02");
+ test_one("now");
+ test_one("yesterday");
+ test_one("today");
+ test_one("tomorrow");
+ test_one("+2d");
+ test_one("+2y 4d");
+ test_one("5months ago");
+
+ return 0;
+}
diff --git a/src/test/test-efivars.c b/src/test/test-efivars.c
new file mode 100644
index 0000000000..43ea5917b6
--- /dev/null
+++ b/src/test/test-efivars.c
@@ -0,0 +1,47 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "log.h"
+#include "efivars.h"
+
+int main(int argc, char* argv[]) {
+ char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)];
+ int r;
+ dual_timestamp fw, l, k;
+
+ dual_timestamp_from_monotonic(&k, 0);
+
+ r = efi_get_boot_timestamps(NULL, &fw, &l);
+ if (r < 0) {
+ log_error("Failed to read variables: %s", strerror(-r));
+ return 1;
+ }
+
+ log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0));
+ log_info("Loader began %s before kernel.", format_timespan(s, sizeof(s), l.monotonic, 0));
+
+ log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime));
+ log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime));
+ log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime));
+
+ return 0;
+}
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
new file mode 100644
index 0000000000..0f3862226a
--- /dev/null
+++ b/src/test/test-engine.c
@@ -0,0 +1,99 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "manager.h"
+
+int main(int argc, char *argv[]) {
+ Manager *m = NULL;
+ Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
+ Job *j;
+
+ assert_se(set_unit_path("test") >= 0);
+
+ assert_se(manager_new(SYSTEMD_SYSTEM, &m) >= 0);
+
+ printf("Load1:\n");
+ assert_se(manager_load_unit(m, "a.service", NULL, NULL, &a) >= 0);
+ assert_se(manager_load_unit(m, "b.service", NULL, NULL, &b) >= 0);
+ assert_se(manager_load_unit(m, "c.service", NULL, NULL, &c) >= 0);
+ manager_dump_units(m, stdout, "\t");
+
+ printf("Test1: (Trivial)\n");
+ assert_se(manager_add_job(m, JOB_START, c, JOB_REPLACE, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Load2:\n");
+ manager_clear_jobs(m);
+ assert_se(manager_load_unit(m, "d.service", NULL, NULL, &d) >= 0);
+ assert_se(manager_load_unit(m, "e.service", NULL, NULL, &e) >= 0);
+ manager_dump_units(m, stdout, "\t");
+
+ printf("Test2: (Cyclic Order, Unfixable)\n");
+ assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -ENOEXEC);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
+ assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Test4: (Identical transaction)\n");
+ assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Load3:\n");
+ assert_se(manager_load_unit(m, "g.service", NULL, NULL, &g) >= 0);
+ manager_dump_units(m, stdout, "\t");
+
+ printf("Test5: (Colliding transaction, fail)\n");
+ assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EEXIST);
+
+ printf("Test6: (Colliding transaction, replace)\n");
+ assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Test7: (Unmergeable job type, fail)\n");
+ assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EEXIST);
+
+ printf("Test8: (Mergeable job type, fail)\n");
+ assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Test9: (Unmergeable job type, replace)\n");
+ assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ printf("Load4:\n");
+ assert_se(manager_load_unit(m, "h.service", NULL, NULL, &h) >= 0);
+ manager_dump_units(m, stdout, "\t");
+
+ printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
+ assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, NULL, &j) == 0);
+ manager_dump_jobs(m, stdout, "\t");
+
+ manager_free(m);
+
+ return 0;
+}
diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c
new file mode 100644
index 0000000000..0274e97618
--- /dev/null
+++ b/src/test/test-env-replace.c
@@ -0,0 +1,218 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <string.h>
+
+#include "util.h"
+#include "strv.h"
+#include "env-util.h"
+
+static void test_strv_env_delete(void) {
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
+
+ a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL);
+ assert_se(a);
+
+ b = strv_new("PIEP", "FOO", NULL);
+ assert_se(b);
+
+ c = strv_new("SCHLUMPF", NULL);
+ assert_se(c);
+
+ d = strv_env_delete(a, 2, b, c);
+ assert_se(d);
+
+ assert_se(streq(d[0], "WALDO=WALDO"));
+ assert_se(streq(d[1], "WALDO="));
+ assert_se(strv_length(d) == 2);
+}
+
+static void test_strv_env_unset(void) {
+ _cleanup_strv_free_ char **l = NULL;
+
+ l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
+ assert_se(l);
+
+ assert_se(strv_env_unset(l, "SCHLUMPF") == l);
+
+ assert_se(streq(l[0], "PIEP"));
+ assert_se(streq(l[1], "NANANANA=YES"));
+ assert_se(strv_length(l) == 2);
+}
+
+static void test_strv_env_set(void) {
+ _cleanup_strv_free_ char **l = NULL, **r = NULL;
+
+ l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
+ assert_se(l);
+
+ r = strv_env_set(l, "WALDO=WALDO");
+ assert_se(r);
+
+ assert_se(streq(r[0], "PIEP"));
+ assert_se(streq(r[1], "SCHLUMPF=SMURFF"));
+ assert_se(streq(r[2], "NANANANA=YES"));
+ assert_se(streq(r[3], "WALDO=WALDO"));
+ assert_se(strv_length(r) == 4);
+}
+
+static void test_strv_env_merge(void) {
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL;
+
+ a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL);
+ assert_se(a);
+
+ b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
+ assert_se(b);
+
+ r = strv_env_merge(2, a, b);
+ assert_se(r);
+ assert_se(streq(r[0], "FOO="));
+ assert_se(streq(r[1], "WALDO="));
+ assert_se(streq(r[2], "PIEP"));
+ assert_se(streq(r[3], "SCHLUMPF=SMURFF"));
+ assert_se(streq(r[4], "PIEP="));
+ assert_se(streq(r[5], "NANANANA=YES"));
+ assert_se(strv_length(r) == 6);
+
+ assert_se(strv_env_clean(r) == r);
+ assert_se(streq(r[0], "FOO="));
+ assert_se(streq(r[1], "WALDO="));
+ assert_se(streq(r[2], "SCHLUMPF=SMURFF"));
+ assert_se(streq(r[3], "PIEP="));
+ assert_se(streq(r[4], "NANANANA=YES"));
+ assert_se(strv_length(r) == 5);
+}
+
+static void test_replace_env_arg(void) {
+ const char *env[] = {
+ "FOO=BAR BAR",
+ "BAR=waldo",
+ NULL
+ };
+ const char *line[] = {
+ "FOO$FOO",
+ "FOO$FOOFOO",
+ "FOO${FOO}$FOO",
+ "FOO${FOO}",
+ "${FOO}",
+ "$FOO",
+ "$FOO$FOO",
+ "${FOO}${BAR}",
+ "${FOO",
+ NULL
+ };
+ _cleanup_strv_free_ char **r = NULL;
+
+ r = replace_env_argv((char**) line, (char**) env);
+ assert_se(r);
+ assert_se(streq(r[0], "FOO$FOO"));
+ assert_se(streq(r[1], "FOO$FOOFOO"));
+ assert_se(streq(r[2], "FOOBAR BAR$FOO"));
+ assert_se(streq(r[3], "FOOBAR BAR"));
+ assert_se(streq(r[4], "BAR BAR"));
+ assert_se(streq(r[5], "BAR"));
+ assert_se(streq(r[6], "BAR"));
+ assert_se(streq(r[7], "BAR BARwaldo"));
+ assert_se(streq(r[8], "${FOO"));
+ assert_se(strv_length(r) == 9);
+}
+
+static void test_one_normalize(const char *input, const char *output) {
+ _cleanup_free_ char *t;
+
+ t = normalize_env_assignment(input);
+ assert_se(t);
+ assert_se(streq(t, output));
+}
+
+static void test_normalize_env_assignment(void) {
+ test_one_normalize("foo=bar", "foo=bar");
+ test_one_normalize("=bar", "=bar");
+ test_one_normalize("foo=", "foo=");
+ test_one_normalize("=", "=");
+ test_one_normalize("", "");
+ test_one_normalize("a=\"waldo\"", "a=waldo");
+ test_one_normalize("a=\"waldo", "a=\"waldo");
+ test_one_normalize("a=waldo\"", "a=waldo\"");
+ test_one_normalize("a=\'", "a='");
+ test_one_normalize("a=\'\'", "a=");
+ test_one_normalize(" xyz ", "xyz");
+ test_one_normalize(" xyz = bar ", "xyz=bar");
+ test_one_normalize(" xyz = 'bar ' ", "xyz=bar ");
+ test_one_normalize(" ' xyz' = 'bar ' ", "' xyz'=bar ");
+}
+
+static void test_env_clean(void) {
+ _cleanup_strv_free_ char **e;
+
+ e = strv_new("FOOBAR=WALDO",
+ "FOOBAR=WALDO",
+ "FOOBAR",
+ "F",
+ "X=",
+ "F=F",
+ "=",
+ "=F",
+ "",
+ "0000=000",
+ "äöüß=abcd",
+ "abcd=äöüß",
+ "xyz\n=xyz",
+ "xyz=xyz\n",
+ "another=one",
+ "another=final one",
+ NULL);
+ assert_se(e);
+ assert_se(!strv_env_is_valid(e));
+ assert_se(strv_env_clean(e) == e);
+ assert_se(strv_env_is_valid(e));
+
+ assert_se(streq(e[0], "FOOBAR=WALDO"));
+ assert_se(streq(e[1], "X="));
+ assert_se(streq(e[2], "F=F"));
+ assert_se(streq(e[3], "abcd=äöüß"));
+ assert_se(streq(e[4], "another=final one"));
+ assert_se(e[5] == NULL);
+}
+
+static void test_env_name_is_valid(void) {
+ assert_se(env_name_is_valid("test"));
+
+ assert_se(!env_name_is_valid(NULL));
+ assert_se(!env_name_is_valid(""));
+ assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong"));
+ assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed"));
+}
+
+int main(int argc, char *argv[]) {
+ test_strv_env_delete();
+ test_strv_env_unset();
+ test_strv_env_set();
+ test_strv_env_merge();
+ test_replace_env_arg();
+ test_normalize_env_assignment();
+ test_env_clean();
+ test_env_name_is_valid();
+
+ return 0;
+}
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
new file mode 100644
index 0000000000..d56f7cc856
--- /dev/null
+++ b/src/test/test-fileio.c
@@ -0,0 +1,145 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "fileio.h"
+#include "strv.h"
+#include "env-util.h"
+
+static void test_parse_env_file(void) {
+ char t[] = "/tmp/test-parse-env-file-XXXXXX";
+ int fd, r;
+ FILE *f;
+ _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL,
+ *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL;
+ _cleanup_strv_free_ char **a = NULL, **b = NULL;
+ char **i;
+ unsigned k;
+
+ fd = mkostemp(t, O_CLOEXEC);
+ assert_se(fd >= 0);
+
+ f = fdopen(fd, "w");
+ assert_se(f);
+
+ fputs("one=BAR \n"
+ "# comment\n"
+ " # comment \n"
+ " ; comment \n"
+ " two = bar \n"
+ "invalid line\n"
+ "invalid line #comment\n"
+ "three = \"333\n"
+ "xxxx\"\n"
+ "four = \'44\\\"44\'\n"
+ "five = \'55\\\'55\' \"FIVE\" cinco \n"
+ "six = seis sechs\\\n"
+ " sis\n"
+ "seven=\"sevenval\" #nocomment\n"
+ "eight=eightval #nocomment\n"
+ "export nine=nineval\n"
+ "ten=", f);
+
+ fflush(f);
+ fclose(f);
+
+ r = load_env_file(t, NULL, &a);
+ assert_se(r >= 0);
+
+ STRV_FOREACH(i, a)
+ log_info("Got: <%s>", *i);
+
+ assert_se(streq(a[0], "one=BAR"));
+ assert_se(streq(a[1], "two=bar"));
+ assert_se(streq(a[2], "three=333\nxxxx"));
+ assert_se(streq(a[3], "four=44\"44"));
+ assert_se(streq(a[4], "five=55\'55FIVEcinco"));
+ assert_se(streq(a[5], "six=seis sechs sis"));
+ assert_se(streq(a[6], "seven=sevenval#nocomment"));
+ assert_se(streq(a[7], "eight=eightval #nocomment"));
+ assert_se(streq(a[8], "export nine=nineval"));
+ assert_se(streq(a[9], "ten="));
+ assert_se(a[10] == NULL);
+
+ strv_env_clean_log(a, "/tmp/test-fileio");
+
+ k = 0;
+ STRV_FOREACH(i, b) {
+ log_info("Got2: <%s>", *i);
+ assert_se(streq(*i, a[k++]));
+ }
+
+ r = parse_env_file(
+ t, NULL,
+ "one", &one,
+ "two", &two,
+ "three", &three,
+ "four", &four,
+ "five", &five,
+ "six", &six,
+ "seven", &seven,
+ "eight", &eight,
+ "export nine", &nine,
+ "ten", &ten,
+ NULL);
+
+ assert_se(r >= 0);
+
+ log_info("one=[%s]", strna(one));
+ log_info("two=[%s]", strna(two));
+ log_info("three=[%s]", strna(three));
+ log_info("four=[%s]", strna(four));
+ log_info("five=[%s]", strna(five));
+ log_info("six=[%s]", strna(six));
+ log_info("seven=[%s]", strna(seven));
+ log_info("eight=[%s]", strna(eight));
+ log_info("export nine=[%s]", strna(nine));
+ log_info("ten=[%s]", strna(nine));
+
+ assert_se(streq(one, "BAR"));
+ assert_se(streq(two, "bar"));
+ assert_se(streq(three, "333\nxxxx"));
+ assert_se(streq(four, "44\"44"));
+ assert_se(streq(five, "55\'55FIVEcinco"));
+ assert_se(streq(six, "seis sechs sis"));
+ assert_se(streq(seven, "sevenval#nocomment"));
+ assert_se(streq(eight, "eightval #nocomment"));
+ assert_se(streq(nine, "nineval"));
+ assert_se(ten == NULL);
+
+ r = write_env_file("/tmp/test-fileio", a);
+ assert_se(r >= 0);
+
+ r = load_env_file("/tmp/test-fileio", NULL, &b);
+ assert_se(r >= 0);
+
+ unlink(t);
+ unlink("/tmp/test-fileio");
+}
+
+int main(int argc, char *argv[]) {
+ test_parse_env_file();
+ return 0;
+}
diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c
new file mode 100644
index 0000000000..2aead79bb1
--- /dev/null
+++ b/src/test/test-hashmap.c
@@ -0,0 +1,508 @@
+/***
+ This file is part of systemd
+
+ Copyright 2013 Daniel Buch
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include "strv.h"
+#include "util.h"
+#include "hashmap.h"
+
+static void test_hashmap_replace(void) {
+ Hashmap *m;
+ char *val1, *val2, *val3, *val4, *val5, *r;
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ val1 = strdup("val1");
+ assert_se(val1);
+ val2 = strdup("val2");
+ assert_se(val2);
+ val3 = strdup("val3");
+ assert_se(val3);
+ val4 = strdup("val4");
+ assert_se(val4);
+ val5 = strdup("val5");
+ assert_se(val5);
+
+ hashmap_put(m, "key 1", val1);
+ hashmap_put(m, "key 2", val2);
+ hashmap_put(m, "key 3", val3);
+ hashmap_put(m, "key 4", val4);
+
+ hashmap_replace(m, "key 3", val1);
+ r = hashmap_get(m, "key 3");
+ assert_se(streq(r, "val1"));
+
+ hashmap_replace(m, "key 5", val5);
+ r = hashmap_get(m, "key 5");
+ assert_se(streq(r, "val5"));
+
+ free(val1);
+ free(val2);
+ free(val3);
+ free(val4);
+ free(val5);
+ hashmap_free(m);
+}
+
+static void test_hashmap_copy(void) {
+ Hashmap *m, *copy;
+ char *val1, *val2, *val3, *val4, *r;
+
+ val1 = strdup("val1");
+ assert_se(val1);
+ val2 = strdup("val2");
+ assert_se(val2);
+ val3 = strdup("val3");
+ assert_se(val3);
+ val4 = strdup("val4");
+ assert_se(val4);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "key 1", val1);
+ hashmap_put(m, "key 2", val2);
+ hashmap_put(m, "key 3", val3);
+ hashmap_put(m, "key 4", val4);
+
+ copy = hashmap_copy(m);
+
+ r = hashmap_get(copy, "key 1");
+ assert_se(streq(r, "val1"));
+ r = hashmap_get(copy, "key 2");
+ assert_se(streq(r, "val2"));
+ r = hashmap_get(copy, "key 3");
+ assert_se(streq(r, "val3"));
+ r = hashmap_get(copy, "key 4");
+ assert_se(streq(r, "val4"));
+
+ hashmap_free_free(copy);
+ hashmap_free(m);
+}
+
+static void test_hashmap_get_strv(void) {
+ Hashmap *m;
+ char **strv;
+ char *val1, *val2, *val3, *val4;
+
+ val1 = strdup("val1");
+ assert_se(val1);
+ val2 = strdup("val2");
+ assert_se(val2);
+ val3 = strdup("val3");
+ assert_se(val3);
+ val4 = strdup("val4");
+ assert_se(val4);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "key 1", val1);
+ hashmap_put(m, "key 2", val2);
+ hashmap_put(m, "key 3", val3);
+ hashmap_put(m, "key 4", val4);
+
+ strv = hashmap_get_strv(m);
+
+ assert_se(streq(strv[0], "val1"));
+ assert_se(streq(strv[1], "val2"));
+ assert_se(streq(strv[2], "val3"));
+ assert_se(streq(strv[3], "val4"));
+
+ strv_free(strv);
+
+ hashmap_free(m);
+}
+
+static void test_hashmap_move_one(void) {
+ Hashmap *m, *n;
+ char *val1, *val2, *val3, *val4, *r;
+
+ val1 = strdup("val1");
+ assert_se(val1);
+ val2 = strdup("val2");
+ assert_se(val2);
+ val3 = strdup("val3");
+ assert_se(val3);
+ val4 = strdup("val4");
+ assert_se(val4);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+ n = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "key 1", val1);
+ hashmap_put(m, "key 2", val2);
+ hashmap_put(m, "key 3", val3);
+ hashmap_put(m, "key 4", val4);
+
+ hashmap_move_one(n, m, "key 3");
+ hashmap_move_one(n, m, "key 4");
+
+ r = hashmap_get(n, "key 3");
+ assert_se(r && streq(r, "val3"));
+ r = hashmap_get(n, "key 4");
+ assert_se(r && streq(r, "val4"));
+ r = hashmap_get(m, "key 3");
+ assert_se(!r);
+
+
+ hashmap_free_free(m);
+ hashmap_free_free(n);
+}
+
+static void test_hashmap_next(void) {
+ Hashmap *m;
+ char *val1, *val2, *val3, *val4, *r;
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+ val1 = strdup("val1");
+ assert_se(val1);
+ val2 = strdup("val2");
+ assert_se(val2);
+ val3 = strdup("val3");
+ assert_se(val3);
+ val4 = strdup("val4");
+ assert_se(val4);
+
+ hashmap_put(m, "key 1", val1);
+ hashmap_put(m, "key 2", val2);
+ hashmap_put(m, "key 3", val3);
+ hashmap_put(m, "key 4", val4);
+
+ r = hashmap_next(m, "key 1");
+ assert_se(streq(r, val2));
+ r = hashmap_next(m, "key 2");
+ assert_se(streq(r, val3));
+ r = hashmap_next(m, "key 3");
+ assert_se(streq(r, val4));
+ r = hashmap_next(m, "key 4");
+ assert_se(!r);
+
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_update(void) {
+ Hashmap *m;
+ char *val1, *val2, *r;
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+ val1 = strdup("old_value");
+ assert_se(val1);
+ val2 = strdup("new_value");
+ assert_se(val2);
+
+ hashmap_put(m, "key 1", val1);
+ r = hashmap_get(m, "key 1");
+ assert_se(streq(r, "old_value"));
+
+ hashmap_update(m, "key 1", val2);
+ r = hashmap_get(m, "key 1");
+ assert_se(streq(r, "new_value"));
+
+ free(val1);
+ free(val2);
+ hashmap_free(m);
+}
+
+static void test_hashmap_put(void) {
+ Hashmap *m;
+ int valid_hashmap_put;
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ valid_hashmap_put = hashmap_put(m, "key 1", (void*) (const char *) "val 1");
+ assert_se(valid_hashmap_put == 1);
+
+ assert_se(m);
+ hashmap_free(m);
+}
+
+static void test_hashmap_ensure_allocated(void) {
+ Hashmap *m;
+ int valid_hashmap;
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ valid_hashmap = hashmap_ensure_allocated(&m, string_hash_func, string_compare_func);
+ assert_se(valid_hashmap == 0);
+
+ assert_se(m);
+ hashmap_free(m);
+}
+
+static void test_hashmap_foreach_key(void) {
+ Hashmap *m;
+ Iterator i;
+ bool key_found[] = { false, false, false, false };
+ const char *s;
+ const char *key;
+ static const char key_table[] =
+ "key 1\0"
+ "key 2\0"
+ "key 3\0"
+ "key 4\0";
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ NULSTR_FOREACH(key, key_table)
+ hashmap_put(m, key, (void*) (const char*) "my dummy val");
+
+ HASHMAP_FOREACH_KEY(s, key, m, i) {
+ if (!key_found[0] && streq(key, "key 1"))
+ key_found[0] = true;
+ else if (!key_found[1] && streq(key, "key 2"))
+ key_found[1] = true;
+ else if (!key_found[2] && streq(key, "key 3"))
+ key_found[2] = true;
+ else if (!key_found[3] && streq(key, "fail"))
+ key_found[3] = true;
+ }
+
+ assert_se(m);
+ assert_se(key_found[0] && key_found[1] && key_found[2] && !key_found[3]);
+
+ hashmap_free(m);
+}
+
+static void test_hashmap_foreach(void) {
+ Hashmap *m;
+ Iterator i;
+ bool value_found[] = { false, false, false, false };
+ char *val1, *val2, *val3, *val4, *s;
+
+ val1 = strdup("my val1");
+ assert_se(val1);
+ val2 = strdup("my val2");
+ assert_se(val2);
+ val3 = strdup("my val3");
+ assert_se(val3);
+ val4 = strdup("my val4");
+ assert_se(val4);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "Key 1", val1);
+ hashmap_put(m, "Key 2", val2);
+ hashmap_put(m, "Key 3", val3);
+ hashmap_put(m, "Key 4", val4);
+
+ HASHMAP_FOREACH(s, m, i) {
+ if (!value_found[0] && streq(s, val1))
+ value_found[0] = true;
+ else if (!value_found[1] && streq(s, val2))
+ value_found[1] = true;
+ else if (!value_found[2] && streq(s, val3))
+ value_found[2] = true;
+ else if (!value_found[3] && streq(s, val4))
+ value_found[3] = true;
+ }
+
+ assert_se(m);
+ assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]);
+
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_foreach_backwards(void) {
+ Hashmap *m;
+ Iterator i;
+ char *val1, *val2, *val3, *val4, *s;
+ bool value_found[] = { false, false, false, false };
+
+ val1 = strdup("my val1");
+ assert_se(val1);
+ val2 = strdup("my val2");
+ assert_se(val2);
+ val3 = strdup("my val3");
+ assert_se(val3);
+ val4 = strdup("my val4");
+ assert_se(val4);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+ hashmap_put(m, "Key 1", val1);
+ hashmap_put(m, "Key 2", val2);
+ hashmap_put(m, "Key 3", val3);
+ hashmap_put(m, "Key 4", val4);
+
+ HASHMAP_FOREACH_BACKWARDS(s, m, i) {
+ if (!value_found[0] && streq(s, val1))
+ value_found[0] = true;
+ else if (!value_found[1] && streq(s, val2))
+ value_found[1] = true;
+ else if (!value_found[2] && streq(s, val3))
+ value_found[2] = true;
+ else if (!value_found[3] && streq(s, val4))
+ value_found[3] = true;
+ }
+
+ assert_se(m);
+ assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]);
+
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_merge(void) {
+ Hashmap *m;
+ Hashmap *n;
+ char *val1, *val2, *val3, *val4, *r;
+
+ val1 = strdup("my val1");
+ assert_se(val1);
+ val2 = strdup("my val2");
+ assert_se(val2);
+ val3 = strdup("my val3");
+ assert_se(val3);
+ val4 = strdup("my val4");
+ assert_se(val4);
+
+ n = hashmap_new(string_hash_func, string_compare_func);
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "Key 1", val1);
+ hashmap_put(m, "Key 2", val2);
+ hashmap_put(n, "Key 3", val3);
+ hashmap_put(n, "Key 4", val4);
+
+ assert_se(hashmap_merge(m, n) == 0);
+ r = hashmap_get(m, "Key 3");
+ assert_se(r && streq(r, "my val3"));
+ r = hashmap_get(m, "Key 4");
+ assert_se(r && streq(r, "my val4"));
+
+ assert_se(n);
+ assert_se(m);
+ hashmap_free(n);
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_contains(void) {
+ Hashmap *m;
+ char *val1;
+
+ val1 = strdup("my val");
+ assert_se(val1);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ assert_se(!hashmap_contains(m, "Key 1"));
+ hashmap_put(m, "Key 1", val1);
+ assert_se(hashmap_contains(m, "Key 1"));
+
+ assert_se(m);
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_isempty(void) {
+ Hashmap *m;
+ char *val1;
+
+ val1 = strdup("my val");
+ assert_se(val1);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ assert_se(hashmap_isempty(m));
+ hashmap_put(m, "Key 1", val1);
+ assert_se(!hashmap_isempty(m));
+
+ assert_se(m);
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_size(void) {
+ Hashmap *m;
+ char *val1, *val2, *val3, *val4;
+
+ val1 = strdup("my val");
+ assert_se(val1);
+ val2 = strdup("my val");
+ assert_se(val2);
+ val3 = strdup("my val");
+ assert_se(val3);
+ val4 = strdup("my val");
+ assert_se(val4);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "Key 1", val1);
+ hashmap_put(m, "Key 2", val2);
+ hashmap_put(m, "Key 3", val3);
+ hashmap_put(m, "Key 4", val4);
+
+ assert_se(m);
+ assert_se(hashmap_size(m) == 4);
+ hashmap_free_free(m);
+}
+
+static void test_hashmap_get(void) {
+ Hashmap *m;
+ char *r;
+ char *val;
+
+ val = strdup("my val");
+ assert_se(val);
+
+ m = hashmap_new(string_hash_func, string_compare_func);
+
+ hashmap_put(m, "Key 1", val);
+
+ r = hashmap_get(m, "Key 1");
+ assert_se(streq(r, val));
+
+ assert_se(m);
+ hashmap_free_free(m);
+}
+
+static void test_uint64_compare_func(void) {
+ assert_se(uint64_compare_func("a", "a") == 0);
+ assert_se(uint64_compare_func("a", "b") == -1);
+ assert_se(uint64_compare_func("b", "a") == 1);
+}
+
+static void test_trivial_compare_func(void) {
+ assert_se(trivial_compare_func(INT_TO_PTR('a'), INT_TO_PTR('a')) == 0);
+ assert_se(trivial_compare_func(INT_TO_PTR('a'), INT_TO_PTR('b')) == -1);
+ assert_se(trivial_compare_func(INT_TO_PTR('b'), INT_TO_PTR('a')) == 1);
+}
+
+static void test_string_compare_func(void) {
+ assert_se(!string_compare_func("fred", "wilma") == 0);
+ assert_se(string_compare_func("fred", "fred") == 0);
+}
+
+int main(int argc, const char *argv[])
+{
+ test_hashmap_copy();
+ test_hashmap_get_strv();
+ test_hashmap_move_one();
+ test_hashmap_next();
+ test_hashmap_replace();
+ test_hashmap_update();
+ test_hashmap_put();
+ test_hashmap_ensure_allocated();
+ test_hashmap_foreach();
+ test_hashmap_foreach_backwards();
+ test_hashmap_foreach_key();
+ test_hashmap_contains();
+ test_hashmap_merge();
+ test_hashmap_isempty();
+ test_hashmap_get();
+ test_hashmap_size();
+ test_uint64_compare_func();
+ test_trivial_compare_func();
+ test_string_compare_func();
+}
diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c
new file mode 100644
index 0000000000..ad4f285619
--- /dev/null
+++ b/src/test/test-hostname.c
@@ -0,0 +1,38 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "hostname-setup.h"
+#include "util.h"
+
+int main(int argc, char* argv[]) {
+ int r;
+
+ r = hostname_setup();
+ if (r < 0)
+ fprintf(stderr, "hostname: %s\n", strerror(-r));
+
+ return 0;
+}
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
new file mode 100644
index 0000000000..2ed8e292e6
--- /dev/null
+++ b/src/test/test-id128.c
@@ -0,0 +1,75 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include <systemd/sd-id128.h>
+
+#include "util.h"
+#include "macro.h"
+
+#define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10)
+#define STR_WALDI "0102030405060708090a0b0c0d0e0f10"
+#define UUID_WALDI "01020304-0506-0708-090a-0b0c0d0e0f10"
+
+int main(int argc, char *argv[]) {
+ sd_id128_t id, id2;
+ char t[33];
+ _cleanup_free_ char *b = NULL;
+
+ assert_se(sd_id128_randomize(&id) == 0);
+ printf("random: %s\n", sd_id128_to_string(id, t));
+
+ assert_se(sd_id128_from_string(t, &id2) == 0);
+ assert_se(sd_id128_equal(id, id2));
+
+ assert_se(sd_id128_get_machine(&id) == 0);
+ printf("machine: %s\n", sd_id128_to_string(id, t));
+
+ assert_se(sd_id128_get_boot(&id) == 0);
+ printf("boot: %s\n", sd_id128_to_string(id, t));
+
+ printf("waldi: %s\n", sd_id128_to_string(ID128_WALDI, t));
+ assert_se(streq(t, STR_WALDI));
+
+ assert_se(asprintf(&b, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 32);
+ printf("waldi2: %s\n", b);
+ assert_se(streq(t, b));
+
+ assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0);
+ assert_se(sd_id128_equal(id, ID128_WALDI));
+
+ assert_se(sd_id128_from_string("", &id) < 0);
+ assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f101", &id) < 0);
+ assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f10-", &id) < 0);
+ assert_se(sd_id128_from_string("01020304-0506-0708-090a0b0c0d0e0f10", &id) < 0);
+ assert_se(sd_id128_from_string("010203040506-0708-090a-0b0c0d0e0f10", &id) < 0);
+
+ assert_se(id128_is_valid(STR_WALDI));
+ assert_se(id128_is_valid(UUID_WALDI));
+ assert_se(!id128_is_valid(""));
+ assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f101"));
+ assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f10-"));
+ assert_se(!id128_is_valid("01020304-0506-0708-090a0b0c0d0e0f10"));
+ assert_se(!id128_is_valid("010203040506-0708-090a-0b0c0d0e0f10"));
+
+ return 0;
+}
diff --git a/src/test/test-install.c b/src/test/test-install.c
new file mode 100644
index 0000000000..2c1b9efcb8
--- /dev/null
+++ b/src/test/test-install.c
@@ -0,0 +1,265 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "path-util.h"
+#include "install.h"
+
+static void dump_changes(UnitFileChange *c, unsigned n) {
+ unsigned i;
+
+ assert(n == 0 || c);
+
+ for (i = 0; i < n; i++) {
+ if (c[i].type == UNIT_FILE_UNLINK)
+ printf("rm '%s'\n", c[i].path);
+ else if (c[i].type == UNIT_FILE_SYMLINK)
+ printf("ln -s '%s' '%s'\n", c[i].source, c[i].path);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ Hashmap *h;
+ UnitFileList *p;
+ Iterator i;
+ int r;
+ const char *const files[] = { "avahi-daemon.service", NULL };
+ const char *const files2[] = { "/home/lennart/test.service", NULL };
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+
+ h = hashmap_new(string_hash_func, string_compare_func);
+ r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
+ assert_se(r == 0);
+
+ HASHMAP_FOREACH(p, h, i) {
+ UnitFileState s;
+
+ s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(p->path));
+
+ assert_se(p->state == s);
+
+ fprintf(stderr, "%s (%s)\n",
+ p->path,
+ unit_file_state_to_string(p->state));
+ }
+
+ unit_file_list_free(h);
+
+ log_error("enable");
+
+ r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ log_error("enable2");
+
+ r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED);
+
+ log_error("disable");
+
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED);
+
+ log_error("mask");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
+ assert_se(r >= 0);
+ log_error("mask2");
+ r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED);
+
+ log_error("unmask");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
+ assert_se(r >= 0);
+ log_error("unmask2");
+ r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED);
+
+ log_error("mask");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED);
+
+ log_error("disable");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
+ assert_se(r >= 0);
+ log_error("disable2");
+ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED);
+
+ log_error("umask");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED);
+
+ log_error("enable files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == UNIT_FILE_ENABLED);
+
+ log_error("disable files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == _UNIT_FILE_STATE_INVALID);
+
+ log_error("link files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == UNIT_FILE_LINKED);
+
+ log_error("disable files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == _UNIT_FILE_STATE_INVALID);
+
+ log_error("link files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == UNIT_FILE_LINKED);
+
+ log_error("reenable files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_reenable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == UNIT_FILE_ENABLED);
+
+ log_error("disable files2");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files2[0])) == _UNIT_FILE_STATE_INVALID);
+ log_error("preset files");
+ changes = NULL;
+ n_changes = 0;
+
+ r = unit_file_preset(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
+ assert_se(r >= 0);
+
+ dump_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, path_get_file_name(files[0])) == UNIT_FILE_ENABLED);
+
+ return 0;
+}
diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c
new file mode 100644
index 0000000000..1066374436
--- /dev/null
+++ b/src/test/test-job-type.c
@@ -0,0 +1,105 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "job.h"
+#include "unit.h"
+#include "service.h"
+
+int main(int argc, char*argv[]) {
+ JobType a, b, c, ab, bc, ab_c, bc_a, a_bc;
+ const ServiceState test_states[] = { SERVICE_DEAD, SERVICE_RUNNING };
+ unsigned i;
+ bool merged_ab;
+
+ /* fake a unit */
+ static Service s = {
+ .meta.load_state = UNIT_LOADED,
+ .type = SERVICE_SIMPLE,
+ };
+ Unit *u = UNIT(&s);
+
+ for (i = 0; i < ELEMENTSOF(test_states); i++) {
+ s.state = test_states[i];
+ printf("\nWith collapsing for service state %s\n"
+ "=========================================\n", service_state_to_string(s.state));
+ for (a = 0; a < _JOB_TYPE_MAX_MERGING; a++) {
+ for (b = 0; b < _JOB_TYPE_MAX_MERGING; b++) {
+
+ ab = a;
+ merged_ab = (job_type_merge_and_collapse(&ab, b, u) >= 0);
+
+ if (!job_type_is_mergeable(a, b)) {
+ assert(!merged_ab);
+ printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b));
+ continue;
+ }
+
+ assert(merged_ab);
+ printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(ab));
+
+ for (c = 0; c < _JOB_TYPE_MAX_MERGING; c++) {
+
+ /* Verify transitivity of mergeability of job types */
+ assert(!job_type_is_mergeable(a, b) ||
+ !job_type_is_mergeable(b, c) ||
+ job_type_is_mergeable(a, c));
+
+ /* Verify that merged entries can be merged with the same entries
+ * they can be merged with separately */
+ assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(ab, c));
+ assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(ab, c));
+
+ /* Verify that if a merged with b is not mergeable with c, then
+ * either a or b is not mergeable with c either. */
+ assert(job_type_is_mergeable(ab, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c));
+
+ bc = b;
+ if (job_type_merge_and_collapse(&bc, c, u) >= 0) {
+
+ /* Verify associativity */
+
+ ab_c = ab;
+ assert(job_type_merge_and_collapse(&ab_c, c, u) == 0);
+
+ bc_a = bc;
+ assert(job_type_merge_and_collapse(&bc_a, a, u) == 0);
+
+ a_bc = a;
+ assert(job_type_merge_and_collapse(&a_bc, bc, u) == 0);
+
+ assert(ab_c == bc_a);
+ assert(ab_c == a_bc);
+
+ printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(ab_c));
+ }
+ }
+ }
+ }
+ }
+
+
+ return 0;
+}
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
new file mode 100644
index 0000000000..caa3b4d14c
--- /dev/null
+++ b/src/test/test-libudev.c
@@ -0,0 +1,520 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+
+#include "libudev.h"
+#include "util.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static void log_fn(struct udev *udev,
+ int priority, const char *file, int line, const char *fn,
+ const char *format, va_list args)
+{
+ printf("test-libudev: %s %s:%d ", fn, file, line);
+ vprintf(format, args);
+}
+
+static void print_device(struct udev_device *device)
+{
+ const char *str;
+ dev_t devnum;
+ int count;
+ struct udev_list_entry *list_entry;
+
+ printf("*** device: %p ***\n", device);
+ str = udev_device_get_action(device);
+ if (str != NULL)
+ printf("action: '%s'\n", str);
+
+ str = udev_device_get_syspath(device);
+ printf("syspath: '%s'\n", str);
+
+ str = udev_device_get_sysname(device);
+ printf("sysname: '%s'\n", str);
+
+ str = udev_device_get_sysnum(device);
+ if (str != NULL)
+ printf("sysnum: '%s'\n", str);
+
+ str = udev_device_get_devpath(device);
+ printf("devpath: '%s'\n", str);
+
+ str = udev_device_get_subsystem(device);
+ if (str != NULL)
+ printf("subsystem: '%s'\n", str);
+
+ str = udev_device_get_devtype(device);
+ if (str != NULL)
+ printf("devtype: '%s'\n", str);
+
+ str = udev_device_get_driver(device);
+ if (str != NULL)
+ printf("driver: '%s'\n", str);
+
+ str = udev_device_get_devnode(device);
+ if (str != NULL)
+ printf("devname: '%s'\n", str);
+
+ devnum = udev_device_get_devnum(device);
+ if (major(devnum) > 0)
+ printf("devnum: %u:%u\n", major(devnum), minor(devnum));
+
+ count = 0;
+ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
+ printf("link: '%s'\n", udev_list_entry_get_name(list_entry));
+ count++;
+ }
+ if (count > 0)
+ printf("found %i links\n", count);
+
+ count = 0;
+ udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
+ printf("property: '%s=%s'\n",
+ udev_list_entry_get_name(list_entry),
+ udev_list_entry_get_value(list_entry));
+ count++;
+ }
+ if (count > 0)
+ printf("found %i properties\n", count);
+
+ str = udev_device_get_property_value(device, "MAJOR");
+ if (str != NULL)
+ printf("MAJOR: '%s'\n", str);
+
+ str = udev_device_get_sysattr_value(device, "dev");
+ if (str != NULL)
+ printf("attr{dev}: '%s'\n", str);
+
+ printf("\n");
+}
+
+static int test_device(struct udev *udev, const char *syspath)
+{
+ struct udev_device *device;
+
+ printf("looking at device: %s\n", syspath);
+ device = udev_device_new_from_syspath(udev, syspath);
+ if (device == NULL) {
+ printf("no device found\n");
+ return -1;
+ }
+ print_device(device);
+ udev_device_unref(device);
+ return 0;
+}
+
+static int test_device_parents(struct udev *udev, const char *syspath)
+{
+ struct udev_device *device;
+ struct udev_device *device_parent;
+
+ printf("looking at device: %s\n", syspath);
+ device = udev_device_new_from_syspath(udev, syspath);
+ if (device == NULL)
+ return -1;
+
+ printf("looking at parents\n");
+ device_parent = device;
+ do {
+ print_device(device_parent);
+ device_parent = udev_device_get_parent(device_parent);
+ } while (device_parent != NULL);
+
+ printf("looking at parents again\n");
+ device_parent = device;
+ do {
+ print_device(device_parent);
+ device_parent = udev_device_get_parent(device_parent);
+ } while (device_parent != NULL);
+ udev_device_unref(device);
+
+ return 0;
+}
+
+static int test_device_devnum(struct udev *udev)
+{
+ dev_t devnum = makedev(1, 3);
+ struct udev_device *device;
+
+ printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
+ device = udev_device_new_from_devnum(udev, 'c', devnum);
+ if (device == NULL)
+ return -1;
+ print_device(device);
+ udev_device_unref(device);
+ return 0;
+}
+
+static int test_device_subsys_name(struct udev *udev)
+{
+ struct udev_device *device;
+
+ printf("looking up device: 'block':'sda'\n");
+ device = udev_device_new_from_subsystem_sysname(udev, "block", "sda");
+ if (device == NULL)
+ return -1;
+ print_device(device);
+ udev_device_unref(device);
+
+ printf("looking up device: 'subsystem':'pci'\n");
+ device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
+ if (device == NULL)
+ return -1;
+ print_device(device);
+ udev_device_unref(device);
+
+ printf("looking up device: 'drivers':'scsi:sd'\n");
+ device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd");
+ if (device == NULL)
+ return -1;
+ print_device(device);
+ udev_device_unref(device);
+
+ printf("looking up device: 'module':'printk'\n");
+ device = udev_device_new_from_subsystem_sysname(udev, "module", "printk");
+ if (device == NULL)
+ return -1;
+ print_device(device);
+ udev_device_unref(device);
+ return 0;
+}
+
+static int test_enumerate_print_list(struct udev_enumerate *enumerate)
+{
+ struct udev_list_entry *list_entry;
+ int count = 0;
+
+ udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
+ struct udev_device *device;
+
+ device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
+ udev_list_entry_get_name(list_entry));
+ if (device != NULL) {
+ printf("device: '%s' (%s)\n",
+ udev_device_get_syspath(device),
+ udev_device_get_subsystem(device));
+ udev_device_unref(device);
+ count++;
+ }
+ }
+ printf("found %i devices\n\n", count);
+ return count;
+}
+
+static int test_monitor(struct udev *udev)
+{
+ struct udev_monitor *udev_monitor = NULL;
+ int fd_ep;
+ int fd_udev = -1;
+ struct epoll_event ep_udev, ep_stdin;
+
+ fd_ep = epoll_create1(EPOLL_CLOEXEC);
+ if (fd_ep < 0) {
+ printf("error creating epoll fd: %m\n");
+ goto out;
+ }
+
+ udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (udev_monitor == NULL) {
+ printf("no socket\n");
+ goto out;
+ }
+ fd_udev = udev_monitor_get_fd(udev_monitor);
+
+ if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 ||
+ udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 ||
+ udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) {
+ printf("filter failed\n");
+ goto out;
+ }
+
+ if (udev_monitor_enable_receiving(udev_monitor) < 0) {
+ printf("bind failed\n");
+ goto out;
+ }
+
+ memset(&ep_udev, 0, sizeof(struct epoll_event));
+ ep_udev.events = EPOLLIN;
+ ep_udev.data.fd = fd_udev;
+ if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
+ printf("fail to add fd to epoll: %m\n");
+ goto out;
+ }
+
+ memset(&ep_stdin, 0, sizeof(struct epoll_event));
+ ep_stdin.events = EPOLLIN;
+ ep_stdin.data.fd = STDIN_FILENO;
+ if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) {
+ printf("fail to add fd to epoll: %m\n");
+ goto out;
+ }
+
+ for (;;) {
+ int fdcount;
+ struct epoll_event ev[4];
+ struct udev_device *device;
+ int i;
+
+ printf("waiting for events from udev, press ENTER to exit\n");
+ fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
+ printf("epoll fd count: %i\n", fdcount);
+
+ for (i = 0; i < fdcount; i++) {
+ if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
+ device = udev_monitor_receive_device(udev_monitor);
+ if (device == NULL) {
+ printf("no device from socket\n");
+ continue;
+ }
+ print_device(device);
+ udev_device_unref(device);
+ } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) {
+ printf("exiting loop\n");
+ goto out;
+ }
+ }
+ }
+out:
+ if (fd_ep >= 0)
+ close(fd_ep);
+ udev_monitor_unref(udev_monitor);
+ return 0;
+}
+
+static int test_queue(struct udev *udev)
+{
+ struct udev_queue *udev_queue;
+ unsigned long long int seqnum;
+ struct udev_list_entry *list_entry;
+
+ udev_queue = udev_queue_new(udev);
+ if (udev_queue == NULL)
+ return -1;
+ seqnum = udev_queue_get_kernel_seqnum(udev_queue);
+ printf("seqnum kernel: %llu\n", seqnum);
+ seqnum = udev_queue_get_udev_seqnum(udev_queue);
+ printf("seqnum udev : %llu\n", seqnum);
+
+ if (udev_queue_get_queue_is_empty(udev_queue))
+ printf("queue is empty\n");
+ printf("get queue list\n");
+ udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
+ printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
+ printf("\n");
+ printf("get queue list again\n");
+ udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
+ printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
+ printf("\n");
+
+ list_entry = udev_queue_get_queued_list_entry(udev_queue);
+ if (list_entry != NULL) {
+ printf("event [%llu] is queued\n", seqnum);
+ seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10);
+ if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum))
+ printf("event [%llu] is not finished\n", seqnum);
+ else
+ printf("event [%llu] is finished\n", seqnum);
+ }
+ printf("\n");
+ udev_queue_unref(udev_queue);
+ return 0;
+}
+
+static int test_enumerate(struct udev *udev, const char *subsystem)
+{
+ struct udev_enumerate *udev_enumerate;
+
+ printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem);
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
+ udev_enumerate_scan_devices(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+
+ printf("enumerate 'net' + duplicated scan + null + zero\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_match_subsystem(udev_enumerate, "net");
+ udev_enumerate_scan_devices(udev_enumerate);
+ udev_enumerate_scan_devices(udev_enumerate);
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_scan_devices(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+
+ printf("enumerate 'block'\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_match_subsystem(udev_enumerate,"block");
+ udev_enumerate_add_match_is_initialized(udev_enumerate);
+ udev_enumerate_scan_devices(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+
+ printf("enumerate 'not block'\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
+ udev_enumerate_scan_devices(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+
+ printf("enumerate 'pci, mem, vc'\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_match_subsystem(udev_enumerate, "pci");
+ udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
+ udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
+ udev_enumerate_scan_devices(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+
+ printf("enumerate 'subsystem'\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_scan_subsystems(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+
+ printf("enumerate 'property IF_FS_*=filesystem'\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
+ udev_enumerate_scan_devices(udev_enumerate);
+ test_enumerate_print_list(udev_enumerate);
+ udev_enumerate_unref(udev_enumerate);
+ return 0;
+}
+
+static int test_hwdb(struct udev *udev, const char *modalias) {
+ struct udev_hwdb * hwdb;
+ struct udev_list_entry *entry;
+
+ hwdb = udev_hwdb_new(udev);
+
+ udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
+ printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
+ printf("\n");
+
+ hwdb = udev_hwdb_unref(hwdb);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct udev *udev = NULL;
+ static const struct option options[] = {
+ { "syspath", required_argument, NULL, 'p' },
+ { "subsystem", required_argument, NULL, 's' },
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ {}
+ };
+ const char *syspath = "/devices/virtual/mem/null";
+ const char *subsystem = NULL;
+ char path[1024];
+
+ udev = udev_new();
+ printf("context: %p\n", udev);
+ if (udev == NULL) {
+ printf("no context\n");
+ return 1;
+ }
+ udev_set_log_fn(udev, log_fn);
+ printf("set log: %p\n", log_fn);
+
+ for (;;) {
+ int option;
+
+ option = getopt_long(argc, argv, "+p:s:dhV", options, NULL);
+ if (option == -1)
+ break;
+
+ switch (option) {
+ case 'p':
+ syspath = optarg;
+ break;
+ case 's':
+ subsystem = optarg;
+ break;
+ case 'd':
+ if (udev_get_log_priority(udev) < LOG_INFO)
+ udev_set_log_priority(udev, LOG_INFO);
+ break;
+ case 'h':
+ printf("--debug --syspath= --subsystem= --help\n");
+ goto out;
+ case 'V':
+ printf("%s\n", VERSION);
+ goto out;
+ default:
+ goto out;
+ }
+ }
+
+ /* add sys path if needed */
+ if (!startswith(syspath, "/sys")) {
+ snprintf(path, sizeof(path), "/sys/%s", syspath);
+ syspath = path;
+ }
+
+ test_device(udev, syspath);
+ test_device_devnum(udev);
+ test_device_subsys_name(udev);
+ test_device_parents(udev, syspath);
+
+ test_enumerate(udev, subsystem);
+
+ test_queue(udev);
+
+ test_hwdb(udev, "usb:v0D50p0011*");
+
+ test_monitor(udev);
+out:
+ udev_unref(udev);
+ return 0;
+}
diff --git a/src/test/test-log.c b/src/test/test-log.c
new file mode 100644
index 0000000000..8dc3d5383f
--- /dev/null
+++ b/src/test/test-log.c
@@ -0,0 +1,53 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stddef.h>
+#include <unistd.h>
+
+#include "log.h"
+
+int main(int argc, char* argv[]) {
+
+ log_set_target(LOG_TARGET_CONSOLE);
+ log_open();
+
+ log_struct(LOG_INFO,
+ "MESSAGE=Waldo PID=%lu", (unsigned long) getpid(),
+ "SERVICE=piepapo",
+ NULL);
+
+ log_set_target(LOG_TARGET_JOURNAL);
+ log_open();
+
+ log_struct(LOG_INFO,
+ "MESSAGE=Foobar PID=%lu", (unsigned long) getpid(),
+ "SERVICE=foobar",
+ NULL);
+
+ log_struct(LOG_INFO,
+ "MESSAGE=Foobar PID=%lu", (unsigned long) getpid(),
+ "FORMAT_STR_TEST=1=%i A=%c 2=%hi 3=%li 4=%lli 1=%p foo=%s 2.5=%g 3.5=%g 4.5=%Lg",
+ (int) 1, 'A', (short) 2, (long int) 3, (long long int) 4, (void*) 1, "foo", (float) 2.5f, (double) 3.5, (long double) 4.5,
+ "SUFFIX=GOT IT",
+ NULL);
+
+ return 0;
+}
diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c
new file mode 100644
index 0000000000..ab330ac840
--- /dev/null
+++ b/src/test/test-loopback.c
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "loopback-setup.h"
+#include "util.h"
+
+int main(int argc, char* argv[]) {
+ int r;
+
+ if ((r = loopback_setup()) < 0)
+ fprintf(stderr, "loopback: %s\n", strerror(-r));
+
+ return 0;
+}
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
new file mode 100644
index 0000000000..ad0d0419c4
--- /dev/null
+++ b/src/test/test-ns.c
@@ -0,0 +1,73 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include "namespace.h"
+#include "execute.h"
+#include "log.h"
+
+int main(int argc, char *argv[]) {
+ const char * const writable[] = {
+ "/home",
+ NULL
+ };
+
+ const char * const readonly[] = {
+ "/",
+ "/usr",
+ "/boot",
+ NULL
+ };
+
+ const char * const inaccessible[] = {
+ "/home/lennart/projects",
+ NULL
+ };
+
+ int r;
+ char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
+ var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX";
+
+ assert_se(mkdtemp(tmp_dir));
+ assert_se(mkdtemp(var_tmp_dir));
+
+ r = setup_namespace((char **) writable,
+ (char **) readonly,
+ (char **) inaccessible,
+ tmp_dir,
+ var_tmp_dir,
+ true,
+ 0);
+ if (r < 0) {
+ log_error("Failed to setup namespace: %s", strerror(-r));
+ return 1;
+ }
+
+ execl("/bin/sh", "/bin/sh", NULL);
+ log_error("execl(): %m");
+
+ return 1;
+}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
new file mode 100644
index 0000000000..127e17803f
--- /dev/null
+++ b/src/test/test-path-util.c
@@ -0,0 +1,89 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+
+#include "path-util.h"
+#include "util.h"
+#include "macro.h"
+
+
+static void test_path(void) {
+ assert_se(path_equal("/goo", "/goo"));
+ assert_se(path_equal("//goo", "/goo"));
+ assert_se(path_equal("//goo/////", "/goo"));
+ assert_se(path_equal("goo/////", "goo"));
+
+ assert_se(path_equal("/goo/boo", "/goo//boo"));
+ assert_se(path_equal("//goo/boo", "/goo/boo//"));
+
+ assert_se(path_equal("/", "///"));
+
+ assert_se(!path_equal("/x", "x/"));
+ assert_se(!path_equal("x/", "/"));
+
+ assert_se(!path_equal("/x/./y", "x/y"));
+ assert_se(!path_equal("x/.y", "x/y"));
+
+ assert_se(path_is_absolute("/"));
+ assert_se(!path_is_absolute("./"));
+
+ assert_se(is_path("/dir"));
+ assert_se(is_path("a/b"));
+ assert_se(!is_path("."));
+
+ assert_se(streq(path_get_file_name("./aa/bb/../file.da."), "file.da."));
+ assert_se(streq(path_get_file_name("/aa///.file"), ".file"));
+ assert_se(streq(path_get_file_name("/aa///file..."), "file..."));
+ assert_se(streq(path_get_file_name("file.../"), ""));
+
+#define test_parent(x, y) { \
+ char *z; \
+ int r = path_get_parent(x, &z); \
+ printf("expected: %s\n", y ? y : "error"); \
+ printf("actual: %s\n", r<0 ? "error" : z); \
+ assert_se((y==NULL) ^ (r==0)); \
+ assert_se(y==NULL || path_equal(z, y)); \
+ }
+
+ test_parent("./aa/bb/../file.da.", "./aa/bb/..");
+ test_parent("/aa///.file", "/aa///");
+ test_parent("/aa///file...", "/aa///");
+ test_parent("file.../", NULL);
+
+ assert_se(path_is_mount_point("/", true));
+ assert_se(path_is_mount_point("/", false));
+
+ {
+ char p1[] = "aaa/bbb////ccc";
+ char p2[] = "//aaa/.////ccc";
+ char p3[] = "/./";
+
+ assert(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc"));
+ assert(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
+ assert(path_equal(path_kill_slashes(p3), "/./"));
+ }
+}
+
+int main(void) {
+ test_path();
+ return 0;
+}
diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c
new file mode 100644
index 0000000000..aeac73973b
--- /dev/null
+++ b/src/test/test-prioq.c
@@ -0,0 +1,166 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+
+#include "util.h"
+#include "set.h"
+#include "prioq.h"
+
+#define SET_SIZE 1024*4
+
+static int unsigned_compare(const void *a, const void *b) {
+ const unsigned *x = a, *y = b;
+
+ if (*x < *y)
+ return -1;
+
+ if (*x > *y)
+ return 1;
+
+ return 0;
+}
+
+static void test_unsigned(void) {
+ unsigned buffer[SET_SIZE], i;
+ Prioq *q;
+
+ srand(0);
+
+ q = prioq_new(trivial_compare_func);
+ assert_se(q);
+
+ for (i = 0; i < ELEMENTSOF(buffer); i++) {
+ unsigned u;
+
+ u = (unsigned) rand();
+ buffer[i] = u;
+ assert_se(prioq_put(q, UINT_TO_PTR(u), NULL) >= 0);
+ }
+
+ qsort(buffer, ELEMENTSOF(buffer), sizeof(buffer[0]), unsigned_compare);
+
+ for (i = 0; i < ELEMENTSOF(buffer); i++) {
+ unsigned u;
+
+ assert_se(prioq_size(q) == ELEMENTSOF(buffer) - i);
+
+ u = PTR_TO_UINT(prioq_pop(q));
+ assert_se(buffer[i] == u);
+ }
+
+ assert_se(prioq_isempty(q));
+ prioq_free(q);
+}
+
+struct test {
+ unsigned value;
+ unsigned idx;
+};
+
+static int test_compare(const void *a, const void *b) {
+ const struct test *x = a, *y = b;
+
+ if (x->value < y->value)
+ return -1;
+
+ if (x->value > y->value)
+ return 1;
+
+ return 0;
+}
+
+static unsigned test_hash(const void *a) {
+ const struct test *x = a;
+
+ return x->value;
+}
+
+static void test_struct(void) {
+ Prioq *q;
+ Set *s;
+ unsigned previous = 0, i;
+ int r;
+
+ srand(0);
+
+ q = prioq_new(test_compare);
+ assert_se(q);
+
+ s = set_new(test_hash, test_compare);
+ assert_se(s);
+
+ for (i = 0; i < SET_SIZE; i++) {
+ struct test *t;
+
+ t = new0(struct test, 1);
+ assert_se(t);
+ t->value = (unsigned) rand();
+
+ r = prioq_put(q, t, &t->idx);
+ assert_se(r >= 0);
+
+ if (i % 4 == 0) {
+ r = set_consume(s, t);
+ assert_se(r >= 0);
+ }
+ }
+
+ for (;;) {
+ struct test *t;
+
+ t = set_steal_first(s);
+ if (!t)
+ break;
+
+ r = prioq_remove(q, t, &t->idx);
+ assert_se(r > 0);
+
+ free(t);
+ }
+
+ for (i = 0; i < SET_SIZE * 3 / 4; i++) {
+ struct test *t;
+
+ assert_se(prioq_size(q) == (SET_SIZE * 3 / 4) - i);
+
+ t = prioq_pop(q);
+ assert_se(t);
+
+ assert_se(previous <= t->value);
+ previous = t->value;
+ free(t);
+ }
+
+ assert_se(prioq_isempty(q));
+ prioq_free(q);
+
+ assert_se(set_isempty(s));
+ set_free(s);
+}
+
+int main(int argc, char* argv[]) {
+
+ test_unsigned();
+ test_struct();
+
+ return 0;
+}
diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c
new file mode 100644
index 0000000000..b1d42d77fd
--- /dev/null
+++ b/src/test/test-replace-var.c
@@ -0,0 +1,46 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "util.h"
+#include "macro.h"
+#include "replace-var.h"
+
+static char *lookup(const char *variable, void *userdata) {
+ return strjoin("<<<", variable, ">>>", NULL);
+}
+
+int main(int argc, char *argv[]) {
+ char *r;
+
+ assert_se(r = replace_var("@@@foobar@xyz@HALLO@foobar@test@@testtest@TEST@...@@@", lookup, NULL));
+ puts(r);
+ assert_se(streq(r, "@@@foobar@xyz<<<HALLO>>>foobar@test@@testtest<<<TEST>>>...@@@"));
+ free(r);
+
+ assert_se(r = strreplace("XYZFFFFXYZFFFFXYZ", "XYZ", "ABC"));
+ puts(r);
+ assert_se(streq(r, "ABCFFFFABCFFFFABC"));
+ free(r);
+
+ return 0;
+}
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
new file mode 100644
index 0000000000..ba0aacf79d
--- /dev/null
+++ b/src/test/test-sched-prio.c
@@ -0,0 +1,92 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Holger Hans Peter Freyther
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sched.h>
+
+#include "manager.h"
+#include "macro.h"
+
+int main(int argc, char *argv[]) {
+ Manager *m;
+ Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
+ Service *ser;
+ FILE *serial = NULL;
+ FDSet *fdset = NULL;
+ int r;
+
+ /* prepare the test */
+ assert_se(set_unit_path(TEST_DIR) >= 0);
+ r = manager_new(SYSTEMD_USER, &m);
+ if (r == -EPERM) {
+ puts("manager_new: Permission denied. Skipping test.");
+ return EXIT_TEST_SKIP;
+ }
+ assert(r >= 0);
+ assert_se(manager_startup(m, serial, fdset) >= 0);
+
+ /* load idle ok */
+ assert_se(manager_load_unit(m, "sched_idle_ok.service", NULL, NULL, &idle_ok) >= 0);
+ assert_se(idle_ok->load_state == UNIT_LOADED);
+ ser = SERVICE(idle_ok);
+ assert_se(ser->exec_context.cpu_sched_policy == SCHED_OTHER);
+ assert_se(ser->exec_context.cpu_sched_priority == 0);
+
+ /*
+ * load idle bad. This should print a warning but we have no way to look at it.
+ */
+ assert_se(manager_load_unit(m, "sched_idle_bad.service", NULL, NULL, &idle_bad) >= 0);
+ assert_se(idle_bad->load_state == UNIT_LOADED);
+ ser = SERVICE(idle_ok);
+ assert_se(ser->exec_context.cpu_sched_policy == SCHED_OTHER);
+ assert_se(ser->exec_context.cpu_sched_priority == 0);
+
+ /*
+ * load rr ok.
+ * Test that the default priority is moving from 0 to 1.
+ */
+ assert_se(manager_load_unit(m, "sched_rr_ok.service", NULL, NULL, &rr_ok) >= 0);
+ assert_se(rr_ok->load_state == UNIT_LOADED);
+ ser = SERVICE(rr_ok);
+ assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
+ assert_se(ser->exec_context.cpu_sched_priority == 1);
+
+ /*
+ * load rr bad.
+ * Test that the value of 0 and 100 is ignored.
+ */
+ assert_se(manager_load_unit(m, "sched_rr_bad.service", NULL, NULL, &rr_bad) >= 0);
+ assert_se(rr_bad->load_state == UNIT_LOADED);
+ ser = SERVICE(rr_bad);
+ assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
+ assert_se(ser->exec_context.cpu_sched_priority == 1);
+
+ /*
+ * load rr change.
+ * Test that anything between 1 and 99 can be set.
+ */
+ assert_se(manager_load_unit(m, "sched_rr_change.service", NULL, NULL, &rr_sched) >= 0);
+ assert_se(rr_sched->load_state == UNIT_LOADED);
+ ser = SERVICE(rr_sched);
+ assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
+ assert_se(ser->exec_context.cpu_sched_priority == 99);
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c
new file mode 100644
index 0000000000..c3cb9c531d
--- /dev/null
+++ b/src/test/test-sleep.c
@@ -0,0 +1,57 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "log.h"
+#include "sleep-config.h"
+#include "strv.h"
+
+int main(int argc, char* argv[]) {
+ _cleanup_strv_free_ char
+ **standby = strv_new("standby", NULL),
+ **mem = strv_new("mem", NULL),
+ **disk = strv_new("disk", NULL),
+ **suspend = strv_new("suspend", NULL),
+ **reboot = strv_new("reboot", NULL),
+ **platform = strv_new("platform", NULL),
+ **shutdown = strv_new("shutdown", NULL),
+ **freez = strv_new("freeze", NULL);
+
+ log_info("Can Standby: %s", yes_no(can_sleep_state(standby) > 0));
+ log_info("Can Suspend: %s", yes_no(can_sleep_state(mem) > 0));
+ log_info("Can Hibernate: %s", yes_no(can_sleep_state(disk) > 0));
+ log_info("Can Hibernate+Suspend (Hybrid-Sleep): %s", yes_no(can_sleep_disk(suspend) > 0));
+ log_info("Can Hibernate+Reboot: %s", yes_no(can_sleep_disk(reboot) > 0));
+ log_info("Can Hibernate+Platform: %s", yes_no(can_sleep_disk(platform) > 0));
+ log_info("Can Hibernate+Shutdown: %s", yes_no(can_sleep_disk(shutdown) > 0));
+ log_info("Can Freeze: %s", yes_no(can_sleep_disk(freez) > 0));
+
+ log_info("Suspend configured and possible: %s", yes_no(can_sleep("suspend") > 0));
+ log_info("Hibernation configured and possible: %s", yes_no(can_sleep("hibernate") > 0));
+ log_info("Hybrid-sleep configured and possible: %s", yes_no(can_sleep("hybrid-sleep") > 0));
+
+ return 0;
+}
diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c
new file mode 100644
index 0000000000..e9b6c033fd
--- /dev/null
+++ b/src/test/test-strbuf.c
@@ -0,0 +1,93 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "strbuf.h"
+#include "strv.h"
+#include "util.h"
+
+static ssize_t add_string(struct strbuf *sb, const char *s) {
+ return strbuf_add_string(sb, s, strlen(s));
+}
+
+static void test_strbuf(void) {
+ struct strbuf *sb;
+ _cleanup_strv_free_ char **l;
+ ssize_t a, b, c, d, e, f, g;
+
+ sb = strbuf_new();
+
+ a = add_string(sb, "waldo");
+ b = add_string(sb, "foo");
+ c = add_string(sb, "bar");
+ d = add_string(sb, "waldo"); /* duplicate */
+ e = add_string(sb, "aldo"); /* duplicate */
+ f = add_string(sb, "do"); /* duplicate */
+ g = add_string(sb, "waldorf"); /* not a duplicate: matches from tail */
+
+ /* check the content of the buffer directly */
+ l = strv_parse_nulstr(sb->buf, sb->len);
+
+ assert(streq(l[0], "")); /* root*/
+ assert(streq(l[1], "waldo"));
+ assert(streq(l[2], "foo"));
+ assert(streq(l[3], "bar"));
+ assert(streq(l[4], "waldorf"));
+
+ assert(sb->nodes_count == 5); /* root + 4 non-duplicates */
+ assert(sb->dedup_count == 3);
+ assert(sb->in_count == 7);
+
+ assert(sb->in_len == 29); /* length of all strings added */
+ assert(sb->dedup_len == 11); /* length of all strings duplicated */
+ assert(sb->len == 23); /* buffer length: in - dedup + \0 for each node */
+
+ /* check the returned offsets and the respective content in the buffer */
+ assert(a == 1);
+ assert(b == 7);
+ assert(c == 11);
+ assert(d == 1);
+ assert(e == 2);
+ assert(f == 4);
+ assert(g == 15);
+
+ assert(streq(sb->buf + a, "waldo"));
+ assert(streq(sb->buf + b, "foo"));
+ assert(streq(sb->buf + c, "bar"));
+ assert(streq(sb->buf + d, "waldo"));
+ assert(streq(sb->buf + e, "aldo"));
+ assert(streq(sb->buf + f, "do"));
+ assert(streq(sb->buf + g, "waldorf"));
+
+ strbuf_complete(sb);
+ assert(sb->root == NULL);
+
+ strbuf_cleanup(sb);
+}
+
+int main(int argc, const char *argv[])
+{
+ test_strbuf();
+
+ return 0;
+}
diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c
new file mode 100644
index 0000000000..5016906ad0
--- /dev/null
+++ b/src/test/test-strip-tab-ansi.c
@@ -0,0 +1,52 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+ char *p;
+
+ assert_se(p = strdup("\tFoobar\tbar\twaldo\t"));
+ assert_se(strip_tab_ansi(&p, NULL));
+ fprintf(stdout, "<%s>\n", p);
+ assert_se(streq(p, " Foobar bar waldo "));
+ free(p);
+
+ assert_se(p = strdup(ANSI_HIGHLIGHT_ON "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF));
+ assert_se(strip_tab_ansi(&p, NULL));
+ fprintf(stdout, "<%s>\n", p);
+ assert_se(streq(p, "Hello world!"));
+ free(p);
+
+ assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT_ON "\x1B[" "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF));
+ assert_se(strip_tab_ansi(&p, NULL));
+ assert_se(streq(p, "\x1B[\x1B[ \x1B[\x1B[Hello world!"));
+ free(p);
+
+ assert_se(p = strdup("\x1B[waldo"));
+ assert_se(strip_tab_ansi(&p, NULL));
+ assert_se(streq(p, "\x1B[waldo"));
+ free(p);
+
+ return 0;
+}
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
new file mode 100644
index 0000000000..074e1bb3d4
--- /dev/null
+++ b/src/test/test-strv.c
@@ -0,0 +1,265 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "util.h"
+#include "specifier.h"
+#include "strv.h"
+
+static void test_specifier_printf(void) {
+ _cleanup_free_ char *w = NULL;
+
+ const Specifier table[] = {
+ { 'a', specifier_string, (char*) "AAAA" },
+ { 'b', specifier_string, (char*) "BBBB" },
+ { 0, NULL, NULL }
+ };
+
+ w = specifier_printf("xxx a=%a b=%b yyy", table, NULL);
+ puts(w);
+
+ assert_se(w);
+ assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
+}
+
+static void test_strv_find(void) {
+ const char * const input_table[] = {
+ "one",
+ "two",
+ "three",
+ NULL
+ };
+
+ assert_se(strv_find((char **)input_table, "three"));
+ assert_se(!strv_find((char **)input_table, "four"));
+}
+
+static void test_strv_find_prefix(void) {
+ const char * const input_table[] = {
+ "one",
+ "two",
+ "three",
+ NULL
+ };
+
+ assert_se(strv_find_prefix((char **)input_table, "o"));
+ assert_se(strv_find_prefix((char **)input_table, "one"));
+ assert_se(strv_find_prefix((char **)input_table, ""));
+ assert_se(!strv_find_prefix((char **)input_table, "xxx"));
+ assert_se(!strv_find_prefix((char **)input_table, "onee"));
+}
+
+static void test_strv_join(void) {
+ _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL;
+
+ const char * const input_table_multiple[] = {
+ "one",
+ "two",
+ "three",
+ NULL
+ };
+ const char * const input_table_one[] = {
+ "one",
+ NULL
+ };
+ const char * const input_table_none[] = {
+ NULL
+ };
+
+ p = strv_join((char **)input_table_multiple, ", ");
+ assert_se(p);
+ assert_se(streq(p, "one, two, three"));
+
+ q = strv_join((char **)input_table_multiple, ";");
+ assert_se(q);
+ assert_se(streq(q, "one;two;three"));
+
+ r = strv_join((char **)input_table_multiple, NULL);
+ assert_se(r);
+ assert_se(streq(r, "one two three"));
+
+ s = strv_join((char **)input_table_one, ", ");
+ assert_se(s);
+ assert_se(streq(s, "one"));
+
+ t = strv_join((char **)input_table_none, ", ");
+ assert_se(t);
+ assert_se(streq(t, ""));
+}
+
+static void test_strv_split_nulstr(void) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char nulstr[] = "str0\0str1\0str2\0str3\0";
+
+ l = strv_split_nulstr (nulstr);
+ assert_se(l);
+
+ assert_se(streq(l[0], "str0"));
+ assert_se(streq(l[1], "str1"));
+ assert_se(streq(l[2], "str2"));
+ assert_se(streq(l[3], "str3"));
+}
+
+static void test_strv_parse_nulstr(void) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
+
+ l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
+ assert_se(l);
+ puts("Parse nulstr:");
+ strv_print(l);
+
+ assert_se(streq(l[0], "fuck"));
+ assert_se(streq(l[1], "fuck2"));
+ assert_se(streq(l[2], "fuck3"));
+ assert_se(streq(l[3], ""));
+ assert_se(streq(l[4], "fuck5"));
+ assert_se(streq(l[5], ""));
+ assert_se(streq(l[6], "xxx"));
+}
+
+static void test_strv_overlap(void) {
+ const char * const input_table[] = {
+ "one",
+ "two",
+ "three",
+ NULL
+ };
+ const char * const input_table_overlap[] = {
+ "two",
+ NULL
+ };
+ const char * const input_table_unique[] = {
+ "four",
+ "five",
+ "six",
+ NULL
+ };
+
+ assert_se(strv_overlap((char **)input_table, (char**)input_table_overlap));
+ assert_se(!strv_overlap((char **)input_table, (char**)input_table_unique));
+}
+
+static void test_strv_sort(void) {
+ const char* input_table[] = {
+ "durian",
+ "apple",
+ "citrus",
+ "CAPITAL LETTERS FIRST",
+ "banana",
+ NULL
+ };
+
+ strv_sort((char **)input_table);
+
+ assert_se(streq(input_table[0], "CAPITAL LETTERS FIRST"));
+ assert_se(streq(input_table[1], "apple"));
+ assert_se(streq(input_table[2], "banana"));
+ assert_se(streq(input_table[3], "citrus"));
+ assert_se(streq(input_table[4], "durian"));
+}
+
+static void test_strv_merge_concat(void) {
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL;
+
+ a = strv_new("without", "suffix", NULL);
+ b = strv_new("with", "suffix", NULL);
+ assert_se(a);
+ assert_se(b);
+
+ c = strv_merge_concat(a, b, "_suffix");
+ assert_se(c);
+
+ assert_se(streq(c[0], "without"));
+ assert_se(streq(c[1], "suffix"));
+ assert_se(streq(c[2], "with_suffix"));
+ assert_se(streq(c[3], "suffix_suffix"));
+}
+
+static void test_strv_merge(void) {
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL;
+
+ a = strv_new("abc", "def", "ghi", NULL);
+ b = strv_new("jkl", "mno", "pqr", NULL);
+ assert_se(a);
+ assert_se(b);
+
+ c = strv_merge(a, b);
+ assert_se(c);
+
+ assert_se(streq(c[0], "abc"));
+ assert_se(streq(c[1], "def"));
+ assert_se(streq(c[2], "ghi"));
+ assert_se(streq(c[3], "jkl"));
+ assert_se(streq(c[4], "mno"));
+ assert_se(streq(c[5], "pqr"));
+
+ assert_se(strv_length(c) == 6);
+}
+
+static void test_strv_append(void) {
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL;
+
+ a = strv_new("test", "test1", NULL);
+ assert_se(a);
+ b = strv_append(a, "test2");
+ c = strv_append(NULL, "test3");
+ assert_se(b);
+ assert_se(c);
+
+ assert_se(streq(b[0], "test"));
+ assert_se(streq(b[1], "test1"));
+ assert_se(streq(b[2], "test2"));
+ assert_se(streq(c[0], "test3"));
+}
+
+static void test_strv_foreach_pair(void) {
+ _cleanup_strv_free_ char **a = NULL;
+ char **x, **y;
+
+ a = strv_new("pair_one", "pair_one",
+ "pair_two", "pair_two",
+ "pair_three", "pair_three",
+ NULL);
+
+ STRV_FOREACH_PAIR(x, y, a) {
+ assert_se(streq(*x, *y));
+ }
+}
+
+int main(int argc, char *argv[]) {
+ test_specifier_printf();
+ test_strv_foreach_pair();
+ test_strv_find();
+ test_strv_find_prefix();
+ test_strv_join();
+ test_strv_split_nulstr();
+ test_strv_parse_nulstr();
+ test_strv_overlap();
+ test_strv_sort();
+ test_strv_merge();
+ test_strv_merge_concat();
+ test_strv_append();
+
+ return 0;
+}
diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c
new file mode 100644
index 0000000000..b7b70d4c15
--- /dev/null
+++ b/src/test/test-strxcpyx.c
@@ -0,0 +1,101 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "util.h"
+#include "strv.h"
+#include "strxcpyx.h"
+
+static void test_strpcpy(void) {
+ char target[25];
+ char *s = target;
+ size_t space_left;
+
+ space_left = sizeof(target);
+ space_left = strpcpy(&s, space_left, "12345");
+ space_left = strpcpy(&s, space_left, "hey hey hey");
+ space_left = strpcpy(&s, space_left, "waldo");
+ space_left = strpcpy(&s, space_left, "ba");
+ space_left = strpcpy(&s, space_left, "r");
+ space_left = strpcpy(&s, space_left, "foo");
+
+ assert(streq(target, "12345hey hey heywaldobar"));
+ assert(space_left == 0);
+}
+
+static void test_strpcpyf(void) {
+ char target[25];
+ char *s = target;
+ size_t space_left;
+
+ space_left = sizeof(target);
+ space_left = strpcpyf(&s, space_left, "space left: %zd. ", space_left);
+ space_left = strpcpyf(&s, space_left, "foo%s", "bar");
+
+ assert(streq(target, "space left: 25. foobar"));
+ assert(space_left == 3);
+}
+
+static void test_strpcpyl(void) {
+ char target[25];
+ char *s = target;
+ size_t space_left;
+
+ space_left = sizeof(target);
+ space_left = strpcpyl(&s, space_left, "waldo", " test", " waldo. ", NULL);
+ space_left = strpcpyl(&s, space_left, "Banana", NULL);
+
+ assert(streq(target, "waldo test waldo. Banana"));
+ assert(space_left == 1);
+}
+
+static void test_strscpy(void) {
+ char target[25];
+ size_t space_left;
+
+ space_left = sizeof(target);
+ space_left = strscpy(target, space_left, "12345");
+
+ assert(streq(target, "12345"));
+ assert(space_left == 20);
+}
+
+static void test_strscpyl(void) {
+ char target[25];
+ size_t space_left;
+
+ space_left = sizeof(target);
+ space_left = strscpyl(target, space_left, "12345", "waldo", "waldo", NULL);
+
+ assert(streq(target, "12345waldowaldo"));
+ assert(space_left == 10);
+}
+
+int main(int argc, char *argv[]) {
+ test_strpcpy();
+ test_strpcpyf();
+ test_strpcpyl();
+ test_strscpy();
+ test_strscpyl();
+
+ return 0;
+}
diff --git a/src/test/test-time.c b/src/test/test-time.c
new file mode 100644
index 0000000000..36a33046a2
--- /dev/null
+++ b/src/test/test-time.c
@@ -0,0 +1,136 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "time-util.h"
+
+static void test_parse_sec(void) {
+ usec_t u;
+
+ assert_se(parse_sec("5s", &u) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC);
+ assert_se(parse_sec("5s500ms", &u) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
+ assert_se(parse_sec(" 5s 500ms ", &u) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
+ assert_se(parse_sec(" 5.5s ", &u) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
+ assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0);
+ assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500);
+ assert_se(parse_sec(" .22s ", &u) >= 0);
+ assert_se(u == 220 * USEC_PER_MSEC);
+ assert_se(parse_sec(" .50y ", &u) >= 0);
+ assert_se(u == USEC_PER_YEAR / 2);
+ assert_se(parse_sec("2.5", &u) >= 0);
+ assert_se(u == 2500 * USEC_PER_MSEC);
+ assert_se(parse_sec(".7", &u) >= 0);
+ assert_se(u == 700 * USEC_PER_MSEC);
+
+ assert_se(parse_sec(" xyz ", &u) < 0);
+ assert_se(parse_sec("", &u) < 0);
+ assert_se(parse_sec(" . ", &u) < 0);
+ assert_se(parse_sec(" 5. ", &u) < 0);
+ assert_se(parse_sec(".s ", &u) < 0);
+}
+
+static void test_parse_nsec(void) {
+ nsec_t u;
+
+ assert_se(parse_nsec("5s", &u) >= 0);
+ assert_se(u == 5 * NSEC_PER_SEC);
+ assert_se(parse_nsec("5s500ms", &u) >= 0);
+ assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
+ assert_se(parse_nsec(" 5s 500ms ", &u) >= 0);
+ assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
+ assert_se(parse_nsec(" 5.5s ", &u) >= 0);
+ assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
+ assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0);
+ assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC);
+ assert_se(parse_nsec(" .22s ", &u) >= 0);
+ assert_se(u == 220 * NSEC_PER_MSEC);
+ assert_se(parse_nsec(" .50y ", &u) >= 0);
+ assert_se(u == NSEC_PER_YEAR / 2);
+ assert_se(parse_nsec("2.5", &u) >= 0);
+ assert_se(u == 2);
+ assert_se(parse_nsec(".7", &u) >= 0);
+ assert_se(u == 0);
+
+ assert_se(parse_nsec(" xyz ", &u) < 0);
+ assert_se(parse_nsec("", &u) < 0);
+ assert_se(parse_nsec(" . ", &u) < 0);
+ assert_se(parse_nsec(" 5. ", &u) < 0);
+ assert_se(parse_nsec(".s ", &u) < 0);
+}
+
+static void test_format_timespan_one(usec_t x, usec_t accuracy) {
+ char *r;
+ char l[FORMAT_TIMESPAN_MAX];
+ usec_t y;
+
+ log_info("%llu (at accuracy %llu)", (unsigned long long) x, (unsigned long long) accuracy);
+
+ r = format_timespan(l, sizeof(l), x, accuracy);
+ assert_se(r);
+
+ log_info(" = <%s>", l);
+
+ assert_se(parse_sec(l, &y) >= 0);
+
+ log_info(" = %llu", (unsigned long long) y);
+
+ if (accuracy <= 0)
+ accuracy = 1;
+
+ assert_se(x / accuracy == y / accuracy);
+}
+
+static void test_format_timespan(usec_t accuracy) {
+ test_format_timespan_one(0, accuracy);
+ test_format_timespan_one(1, accuracy);
+ test_format_timespan_one(1*USEC_PER_SEC, accuracy);
+ test_format_timespan_one(999*USEC_PER_MSEC, accuracy);
+ test_format_timespan_one(1234567, accuracy);
+ test_format_timespan_one(12, accuracy);
+ test_format_timespan_one(123, accuracy);
+ test_format_timespan_one(1234, accuracy);
+ test_format_timespan_one(12345, accuracy);
+ test_format_timespan_one(123456, accuracy);
+ test_format_timespan_one(1234567, accuracy);
+ test_format_timespan_one(12345678, accuracy);
+ test_format_timespan_one(1200000, accuracy);
+ test_format_timespan_one(1230000, accuracy);
+ test_format_timespan_one(1230000, accuracy);
+ test_format_timespan_one(1234000, accuracy);
+ test_format_timespan_one(1234500, accuracy);
+ test_format_timespan_one(1234560, accuracy);
+ test_format_timespan_one(1234567, accuracy);
+ test_format_timespan_one(986087, accuracy);
+ test_format_timespan_one(500 * USEC_PER_MSEC, accuracy);
+ test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy);
+}
+
+int main(int argc, char *argv[]) {
+ test_parse_sec();
+ test_parse_nsec();
+ test_format_timespan(1);
+ test_format_timespan(USEC_PER_MSEC);
+ test_format_timespan(USEC_PER_SEC);
+ return 0;
+}
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
new file mode 100644
index 0000000000..52b61b4206
--- /dev/null
+++ b/src/test/test-udev.c
@@ -0,0 +1,171 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
+ Copyright 2004-2012 Kay Sievers <kay@vrfy.org>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <grp.h>
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/signalfd.h>
+
+#include "missing.h"
+#include "udev.h"
+
+void udev_main_log(struct udev *udev, int priority,
+ const char *file, int line, const char *fn,
+ const char *format, va_list args) {}
+
+static int fake_filesystems(void) {
+ static const struct fakefs {
+ const char *src;
+ const char *target;
+ const char *error;
+ } fakefss[] = {
+ { "test/sys", "/sys", "failed to mount test /sys" },
+ { "test/dev", "/dev", "failed to mount test /dev" },
+ { "test/run", "/run", "failed to mount test /run" },
+ { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" },
+ { "test/run", "/usr/lib/udev/rules.d", "failed to mount empty /usr/lib/udev/rules.d" },
+ };
+ unsigned int i;
+ int err;
+
+ err = unshare(CLONE_NEWNS);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to call unshare(): %m\n");
+ goto out;
+ }
+
+ if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to mount / as private: %m\n");
+ goto out;
+ }
+
+ for (i = 0; i < ELEMENTSOF(fakefss); i++) {
+ err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "%s %m", fakefss[i].error);
+ return err;
+ }
+ }
+out:
+ return err;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct udev *udev;
+ struct udev_event *event = NULL;
+ struct udev_device *dev = NULL;
+ struct udev_rules *rules = NULL;
+ char syspath[UTIL_PATH_SIZE];
+ const char *devpath;
+ const char *action;
+ sigset_t mask, sigmask_orig;
+ int err;
+
+ err = fake_filesystems();
+ if (err < 0)
+ return EXIT_FAILURE;
+
+ udev = udev_new();
+ if (udev == NULL)
+ exit(EXIT_FAILURE);
+ log_debug("version %s\n", VERSION);
+ label_init("/dev");
+
+ sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
+
+ action = argv[1];
+ if (action == NULL) {
+ log_error("action missing\n");
+ goto out;
+ }
+
+ devpath = argv[2];
+ if (devpath == NULL) {
+ log_error("devpath missing\n");
+ goto out;
+ }
+
+ rules = udev_rules_new(udev, 1);
+
+ strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL);
+ dev = udev_device_new_from_syspath(udev, syspath);
+ if (dev == NULL) {
+ log_debug("unknown device '%s'\n", devpath);
+ goto out;
+ }
+
+ udev_device_set_action(dev, action);
+ event = udev_event_new(dev);
+
+ sigfillset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
+ event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+ if (event->fd_signal < 0) {
+ fprintf(stderr, "error creating signalfd\n");
+ goto out;
+ }
+
+ /* do what devtmpfs usually provides us */
+ if (udev_device_get_devnode(dev) != NULL) {
+ mode_t mode = 0600;
+
+ if (streq(udev_device_get_subsystem(dev), "block"))
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (!streq(action, "remove")) {
+ mkdir_parents_label(udev_device_get_devnode(dev), 0755);
+ mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev));
+ } else {
+ unlink(udev_device_get_devnode(dev));
+ util_delete_path(udev, udev_device_get_devnode(dev));
+ }
+ }
+
+ err = udev_event_execute_rules(event, rules, &sigmask_orig);
+ if (err == 0)
+ udev_event_execute_run(event, NULL);
+out:
+ if (event != NULL && event->fd_signal >= 0)
+ close(event->fd_signal);
+ udev_event_unref(event);
+ udev_device_unref(dev);
+ udev_rules_unref(rules);
+ label_finish();
+ udev_unref(udev);
+ if (err != 0)
+ return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
new file mode 100644
index 0000000000..a7fe77af24
--- /dev/null
+++ b/src/test/test-unit-file.c
@@ -0,0 +1,367 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "install.h"
+#include "install-printf.h"
+#include "specifier.h"
+#include "util.h"
+#include "macro.h"
+#include "hashmap.h"
+#include "load-fragment.h"
+#include "strv.h"
+#include "fileio.h"
+
+static void test_unit_file_get_set(void) {
+ int r;
+ Hashmap *h;
+ Iterator i;
+ UnitFileList *p;
+
+ h = hashmap_new(string_hash_func, string_compare_func);
+ assert(h);
+
+ r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
+ log_info("unit_file_get_list: %s", strerror(-r));
+ assert(r >= 0);
+
+ HASHMAP_FOREACH(p, h, i)
+ printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
+
+ unit_file_list_free(h);
+}
+
+static void check_execcommand(ExecCommand *c,
+ const char* path,
+ const char* argv0,
+ const char* argv1,
+ bool ignore) {
+ assert_se(c);
+ log_info("%s %s %s %s",
+ c->path, c->argv[0], c->argv[1], c->argv[2]);
+ assert_se(streq(c->path, path));
+ assert_se(streq(c->argv[0], argv0));
+ assert_se(streq(c->argv[1], argv1));
+ assert_se(c->argv[2] == NULL);
+ assert_se(c->ignore == ignore);
+}
+
+static void test_config_parse_exec(void) {
+ /* int config_parse_exec( */
+ /* const char *filename, */
+ /* unsigned line, */
+ /* const char *section, */
+ /* const char *lvalue, */
+ /* int ltype, */
+ /* const char *rvalue, */
+ /* void *data, */
+ /* void *userdata) */
+ int r;
+
+ ExecCommand *c = NULL, *c1;
+
+ /* basic test */
+ r = config_parse_exec(NULL, "fake", 1, "section",
+ "LValue", 0, "/RValue r1",
+ &c, NULL);
+ assert_se(r >= 0);
+ check_execcommand(c, "/RValue", "/RValue", "r1", false);
+
+ r = config_parse_exec(NULL, "fake", 2, "section",
+ "LValue", 0, "/RValue///slashes/// r1",
+ &c, NULL);
+ /* test slashes */
+ assert_se(r >= 0);
+ c1 = c->command_next;
+ check_execcommand(c1, "/RValue/slashes", "/RValue///slashes///",
+ "r1", false);
+
+ /* honour_argv0 */
+ r = config_parse_exec(NULL, "fake", 3, "section",
+ "LValue", 0, "@/RValue///slashes2/// argv0 r1",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1, "/RValue/slashes2", "argv0", "r1", false);
+
+ /* ignore && honour_argv0 */
+ r = config_parse_exec(NULL, "fake", 4, "section",
+ "LValue", 0, "-@/RValue///slashes3/// argv0a r1",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1,
+ "/RValue/slashes3", "argv0a", "r1", true);
+
+ /* ignore && honour_argv0 */
+ r = config_parse_exec(NULL, "fake", 4, "section",
+ "LValue", 0, "@-/RValue///slashes4/// argv0b r1",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1,
+ "/RValue/slashes4", "argv0b", "r1", true);
+
+ /* ignore && ignore */
+ r = config_parse_exec(NULL, "fake", 4, "section",
+ "LValue", 0, "--/RValue argv0 r1",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c1->command_next == NULL);
+
+ /* ignore && ignore */
+ r = config_parse_exec(NULL, "fake", 4, "section",
+ "LValue", 0, "-@-/RValue argv0 r1",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c1->command_next == NULL);
+
+ /* semicolon */
+ r = config_parse_exec(NULL, "fake", 5, "section",
+ "LValue", 0,
+ "-@/RValue argv0 r1 ; "
+ "/goo/goo boo",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1,
+ "/RValue", "argv0", "r1", true);
+
+ c1 = c1->command_next;
+ check_execcommand(c1,
+ "/goo/goo", "/goo/goo", "boo", false);
+
+ /* trailing semicolon */
+ r = config_parse_exec(NULL, "fake", 5, "section",
+ "LValue", 0,
+ "-@/RValue argv0 r1 ; ",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1,
+ "/RValue", "argv0", "r1", true);
+
+ assert_se(c1->command_next == NULL);
+
+ /* escaped semicolon */
+ r = config_parse_exec(NULL, "fake", 5, "section",
+ "LValue", 0,
+ "/usr/bin/find \\;",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1,
+ "/usr/bin/find", "/usr/bin/find", ";", false);
+
+ exec_command_free_list(c);
+}
+
+#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"
+
+
+static void test_load_env_file_1(void) {
+ _cleanup_strv_free_ char **data = NULL;
+ int r;
+
+ char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_close_ int fd = mkstemp(name);
+ assert(fd >= 0);
+ assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
+
+ r = load_env_file(name, NULL, &data);
+ assert(r == 0);
+ assert(streq(data[0], "a=a"));
+ assert(streq(data[1], "b=bc"));
+ assert(streq(data[2], "d=def"));
+ assert(streq(data[3], "g=g "));
+ assert(streq(data[4], "h=h"));
+ assert(streq(data[5], "i=i"));
+ assert(data[6] == NULL);
+ unlink(name);
+}
+
+static void test_load_env_file_2(void) {
+ _cleanup_strv_free_ char **data = NULL;
+ int r;
+
+ char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_close_ int fd = mkstemp(name);
+ assert(fd >= 0);
+ assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
+
+ r = load_env_file(name, NULL, &data);
+ assert(r == 0);
+ assert(streq(data[0], "a=a"));
+ assert(data[1] == NULL);
+ unlink(name);
+}
+
+static void test_load_env_file_3(void) {
+ _cleanup_strv_free_ char **data = NULL;
+ int r;
+
+ char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_close_ int fd = mkstemp(name);
+ assert(fd >= 0);
+ assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
+
+ r = load_env_file(name, NULL, &data);
+ assert(r == 0);
+ assert(data == NULL);
+ unlink(name);
+}
+
+static void test_load_env_file_4(void) {
+ _cleanup_strv_free_ char **data = NULL;
+ int r;
+
+ char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_close_ int fd = mkstemp(name);
+ assert(fd >= 0);
+ assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
+
+ r = load_env_file(name, NULL, &data);
+ assert(r == 0);
+ assert(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
+ assert(streq(data[1], "MODULE_0=coretemp"));
+ assert(streq(data[2], "MODULE_1=f71882fg"));
+ assert(data[3] == NULL);
+ unlink(name);
+}
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnonnull"
+
+static void test_install_printf(void) {
+ char name[] = "name.service",
+ path[] = "/run/systemd/system/name.service",
+ user[] = "xxxx-no-such-user";
+ InstallInfo i = {name, path, user};
+ InstallInfo i2 = {name, path, NULL};
+ char name3[] = "name@inst.service",
+ path3[] = "/run/systemd/system/name.service";
+ InstallInfo i3 = {name3, path3, user};
+ InstallInfo i4 = {name3, path3, NULL};
+
+ _cleanup_free_ char *mid, *bid, *host;
+
+ assert_se((mid = specifier_machine_id('m', NULL, NULL)));
+ assert_se((bid = specifier_boot_id('b', NULL, NULL)));
+ assert_se((host = gethostname_malloc()));
+
+#define expect(src, pattern, result) \
+ do { \
+ _cleanup_free_ char *t = install_full_printf(&src, pattern); \
+ _cleanup_free_ char \
+ *d1 = strdup(i.name), \
+ *d2 = strdup(i.path), \
+ *d3 = strdup(i.user); \
+ memzero(i.name, strlen(i.name)); \
+ memzero(i.path, strlen(i.path)); \
+ memzero(i.user, strlen(i.user)); \
+ assert(d1 && d2 && d3); \
+ if (result) { \
+ printf("%s\n", t); \
+ assert(streq(t, result)); \
+ } else assert(t == NULL); \
+ strcpy(i.name, d1); \
+ strcpy(i.path, d2); \
+ strcpy(i.user, d3); \
+ } while(false)
+
+ assert_se(setenv("USER", "root", 1) == 0);
+
+ expect(i, "%n", "name.service");
+ expect(i, "%N", "name");
+ expect(i, "%p", "name");
+ expect(i, "%i", "");
+ expect(i, "%u", "xxxx-no-such-user");
+ expect(i, "%U", NULL);
+ expect(i, "%m", mid);
+ expect(i, "%b", bid);
+ expect(i, "%H", host);
+
+ expect(i2, "%u", "root");
+ expect(i2, "%U", "0");
+
+ expect(i3, "%n", "name@inst.service");
+ expect(i3, "%N", "name@inst");
+ expect(i3, "%p", "name");
+ expect(i3, "%u", "xxxx-no-such-user");
+ expect(i3, "%U", NULL);
+ expect(i3, "%m", mid);
+ expect(i3, "%b", bid);
+ expect(i3, "%H", host);
+
+ expect(i4, "%u", "root");
+ expect(i4, "%U", "0");
+}
+#pragma GCC diagnostic pop
+
+int main(int argc, char *argv[]) {
+
+ log_parse_environment();
+ log_open();
+
+ test_unit_file_get_set();
+ test_config_parse_exec();
+ test_load_env_file_1();
+ test_load_env_file_2();
+ test_load_env_file_3();
+ test_load_env_file_4();
+ test_install_printf();
+
+ return 0;
+}
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
new file mode 100644
index 0000000000..86cb2b8da6
--- /dev/null
+++ b/src/test/test-unit-name.c
@@ -0,0 +1,199 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include "manager.h"
+#include "unit.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "install.h"
+#include "specifier.h"
+#include "util.h"
+#include "macro.h"
+
+static void test_replacements(void) {
+#define expect(pattern, repl, expected) \
+ { \
+ _cleanup_free_ char *t = \
+ unit_name_replace_instance(pattern, repl); \
+ puts(t); \
+ assert(streq(t, expected)); \
+ }
+
+ expect("foo@.service", "waldo", "foo@waldo.service");
+ expect("foo@xyz.service", "waldo", "foo@waldo.service");
+ expect("xyz", "waldo", "xyz");
+ expect("", "waldo", "");
+ expect("foo.service", "waldo", "foo.service");
+ expect(".service", "waldo", ".service");
+ expect("foo@", "waldo", "foo@waldo");
+ expect("@bar", "waldo", "@waldo");
+
+ puts("-------------------------------------------------");
+#undef expect
+#define expect(path, suffix, expected) \
+ { \
+ _cleanup_free_ char *k, *t = \
+ unit_name_from_path(path, suffix); \
+ puts(t); \
+ k = unit_name_to_path(t); \
+ puts(k); \
+ assert(streq(k, expected ? expected : path)); \
+ }
+
+ expect("/waldo", ".mount", NULL);
+ expect("/waldo/quuix", ".mount", NULL);
+ expect("/waldo/quuix/", ".mount", "/waldo/quuix");
+ expect("/", ".mount", NULL);
+ expect("///", ".mount", "/");
+
+ puts("-------------------------------------------------");
+#undef expect
+#define expect(pattern, path, suffix, expected) \
+ { \
+ _cleanup_free_ char *t = \
+ unit_name_from_path_instance(pattern, path, suffix); \
+ puts(t); \
+ assert(streq(t, expected)); \
+ }
+
+ expect("waldo", "/waldo", ".mount", "waldo@waldo.mount");
+ expect("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount");
+ expect("waldo", "/", ".mount", "waldo@-.mount");
+ expect("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount");
+
+ puts("-------------------------------------------------");
+#undef expect
+#define expect(pattern) \
+ { \
+ _cleanup_free_ char *k, *t; \
+ assert_se(t = unit_name_mangle(pattern)); \
+ assert_se(k = unit_name_mangle(t)); \
+ puts(t); \
+ assert_se(streq(t, k)); \
+ }
+
+ expect("/home");
+ expect("/dev/sda");
+ expect("üxknürz.service");
+ expect("foobar-meh...waldi.service");
+ expect("_____####----.....service");
+ expect("_____##@;;;,,,##----.....service");
+ expect("xxx@@@@/////\\\\\\\\\\yyy.service");
+
+#undef expect
+}
+
+static int test_unit_printf(void) {
+ Manager *m;
+ Unit *u, *u2;
+ int r;
+
+ _cleanup_free_ char *mid, *bid, *host, *root_uid;
+ struct passwd *root;
+
+ assert_se((mid = specifier_machine_id('m', NULL, NULL)));
+ assert_se((bid = specifier_boot_id('b', NULL, NULL)));
+ assert_se((host = gethostname_malloc()));
+
+ assert_se((root = getpwnam("root")));
+ assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0);
+
+ r = manager_new(SYSTEMD_USER, &m);
+ if (r == -EPERM) {
+ puts("manager_new: Permission denied. Skipping test.");
+ return EXIT_TEST_SKIP;
+ }
+ assert(r == 0);
+
+#define expect(unit, pattern, expected) \
+ { \
+ char *e; \
+ _cleanup_free_ char *t = \
+ unit_full_printf(unit, pattern); \
+ printf("result: %s\nexpect: %s\n", t, expected); \
+ if ((e = endswith(expected, "*"))) \
+ assert(strncmp(t, e, e-expected)); \
+ else \
+ assert(streq(t, expected)); \
+ }
+
+ assert_se(setenv("USER", "root", 1) == 0);
+ assert_se(setenv("HOME", "/root", 1) == 0);
+
+ assert_se(u = unit_new(m, sizeof(Service)));
+ assert_se(unit_add_name(u, "blah.service") == 0);
+ assert_se(unit_add_name(u, "blah.service") == 0);
+
+ /* general tests */
+ expect(u, "%%", "%");
+ expect(u, "%%s", "%s");
+ expect(u, "%", ""); // REALLY?
+
+ /* normal unit */
+ expect(u, "%n", "blah.service");
+ expect(u, "%N", "blah");
+ expect(u, "%p", "blah");
+ expect(u, "%P", "blah");
+ expect(u, "%i", "");
+ expect(u, "%I", "");
+ expect(u, "%u", root->pw_name);
+ expect(u, "%U", root_uid);
+ expect(u, "%h", root->pw_dir);
+ expect(u, "%s", "/bin/sh");
+ expect(u, "%m", mid);
+ expect(u, "%b", bid);
+ expect(u, "%H", host);
+ expect(u, "%t", "/run/user/*");
+
+ /* templated */
+ assert_se(u2 = unit_new(m, sizeof(Service)));
+ assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0);
+ assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0);
+
+ expect(u2, "%n", "blah@foo-foo.service");
+ expect(u2, "%N", "blah@foo-foo");
+ expect(u2, "%p", "blah");
+ expect(u2, "%P", "blah");
+ expect(u2, "%i", "foo-foo");
+ expect(u2, "%I", "foo/foo");
+ expect(u2, "%u", root->pw_name);
+ expect(u2, "%U", root_uid);
+ expect(u2, "%h", root->pw_dir);
+ expect(u2, "%s", "/bin/sh");
+ expect(u2, "%m", mid);
+ expect(u2, "%b", bid);
+ expect(u2, "%H", host);
+ expect(u2, "%t", "/run/user/*");
+
+ return 0;
+}
+
+int main(int argc, char* argv[]) {
+ test_replacements();
+ return test_unit_printf();
+}
diff --git a/src/test/test-util.c b/src/test/test-util.c
new file mode 100644
index 0000000000..4c3a8a6b88
--- /dev/null
+++ b/src/test/test-util.c
@@ -0,0 +1,472 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <errno.h>
+
+#include "util.h"
+
+static void test_streq_ptr(void) {
+ assert_se(streq_ptr(NULL, NULL));
+ assert_se(!streq_ptr("abc", "cdef"));
+}
+
+static void test_first_word(void) {
+ assert_se(first_word("Hello", ""));
+ assert_se(first_word("Hello", "Hello"));
+ assert_se(first_word("Hello world", "Hello"));
+ assert_se(first_word("Hello\tworld", "Hello"));
+ assert_se(first_word("Hello\nworld", "Hello"));
+ assert_se(first_word("Hello\rworld", "Hello"));
+ assert_se(first_word("Hello ", "Hello"));
+
+ assert_se(!first_word("Hello", "Hellooo"));
+ assert_se(!first_word("Hello", "xxxxx"));
+ assert_se(!first_word("Hellooo", "Hello"));
+}
+
+static void test_close_many(void) {
+ int fds[3];
+ char name0[] = "/tmp/test-close-many.XXXXXX";
+ char name1[] = "/tmp/test-close-many.XXXXXX";
+ char name2[] = "/tmp/test-close-many.XXXXXX";
+
+ fds[0] = mkstemp(name0);
+ fds[1] = mkstemp(name1);
+ fds[2] = mkstemp(name2);
+
+ close_many(fds, 2);
+
+ assert_se(fcntl(fds[0], F_GETFD) == -1);
+ assert_se(fcntl(fds[1], F_GETFD) == -1);
+ assert_se(fcntl(fds[2], F_GETFD) >= 0);
+
+ close_nointr_nofail(fds[2]);
+
+ unlink(name0);
+ unlink(name1);
+ unlink(name2);
+}
+
+static void test_parse_boolean(void) {
+ assert_se(parse_boolean("1") == 1);
+ assert_se(parse_boolean("y") == 1);
+ assert_se(parse_boolean("Y") == 1);
+ assert_se(parse_boolean("yes") == 1);
+ assert_se(parse_boolean("YES") == 1);
+ assert_se(parse_boolean("true") == 1);
+ assert_se(parse_boolean("TRUE") == 1);
+ assert_se(parse_boolean("on") == 1);
+ assert_se(parse_boolean("ON") == 1);
+
+ assert_se(parse_boolean("0") == 0);
+ assert_se(parse_boolean("n") == 0);
+ assert_se(parse_boolean("N") == 0);
+ assert_se(parse_boolean("no") == 0);
+ assert_se(parse_boolean("NO") == 0);
+ assert_se(parse_boolean("false") == 0);
+ assert_se(parse_boolean("FALSE") == 0);
+ assert_se(parse_boolean("off") == 0);
+ assert_se(parse_boolean("OFF") == 0);
+
+ assert_se(parse_boolean("garbage") < 0);
+ assert_se(parse_boolean("") < 0);
+}
+
+static void test_parse_pid(void) {
+ int r;
+ pid_t pid;
+
+ r = parse_pid("100", &pid);
+ assert_se(r == 0);
+ assert_se(pid == 100);
+
+ r = parse_pid("0x7FFFFFFF", &pid);
+ assert_se(r == 0);
+ assert_se(pid == 2147483647);
+
+ pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+ r = parse_pid("0", &pid);
+ assert_se(r == -ERANGE);
+ assert_se(pid == 65);
+
+ pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+ r = parse_pid("-100", &pid);
+ assert_se(r == -ERANGE);
+ assert_se(pid == 65);
+
+ pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+ r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
+ assert(r == -ERANGE);
+ assert_se(pid == 65);
+}
+
+static void test_parse_uid(void) {
+ int r;
+ uid_t uid;
+
+ r = parse_uid("100", &uid);
+ assert_se(r == 0);
+ assert_se(uid == 100);
+}
+
+static void test_safe_atolli(void) {
+ int r;
+ long long l;
+
+ r = safe_atolli("12345", &l);
+ assert_se(r == 0);
+ assert_se(l == 12345);
+
+ r = safe_atolli("junk", &l);
+ assert_se(r == -EINVAL);
+}
+
+static void test_safe_atod(void) {
+ int r;
+ double d;
+ char *e;
+
+ r = safe_atod("junk", &d);
+ assert_se(r == -EINVAL);
+
+ r = safe_atod("0.2244", &d);
+ assert_se(r == 0);
+ assert_se(abs(d - 0.2244) < 0.000001);
+
+ r = safe_atod("0,5", &d);
+ assert_se(r == -EINVAL);
+
+ errno = 0;
+ strtod("0,5", &e);
+ assert_se(*e == ',');
+
+ /* Check if this really is locale independent */
+ setlocale(LC_NUMERIC, "de_DE.utf8");
+
+ r = safe_atod("0.2244", &d);
+ assert_se(r == 0);
+ assert_se(abs(d - 0.2244) < 0.000001);
+
+ r = safe_atod("0,5", &d);
+ assert_se(r == -EINVAL);
+
+ errno = 0;
+ assert_se(abs(strtod("0,5", &e) - 0.5) < 0.00001);
+
+ /* And check again, reset */
+ setlocale(LC_NUMERIC, "C");
+
+ r = safe_atod("0.2244", &d);
+ assert_se(r == 0);
+ assert_se(abs(d - 0.2244) < 0.000001);
+
+ r = safe_atod("0,5", &d);
+ assert_se(r == -EINVAL);
+
+ errno = 0;
+ strtod("0,5", &e);
+ assert_se(*e == ',');
+}
+
+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_strstrip(void) {
+ char *r;
+ char input[] = " hello, waldo. ";
+
+ r = strstrip(input);
+ assert_se(streq(r, "hello, waldo."));
+
+}
+
+static void test_delete_chars(void) {
+ char *r;
+ char input[] = " hello, waldo. abc";
+
+ r = delete_chars(input, WHITESPACE);
+ assert_se(streq(r, "hello,waldo.abc"));
+}
+
+static void test_in_charset(void) {
+ assert_se(in_charset("dddaaabbbcccc", "abcd"));
+ assert_se(!in_charset("dddaaabbbcccc", "abc f"));
+}
+
+static void test_hexchar(void) {
+ assert_se(hexchar(0xa) == 'a');
+ assert_se(hexchar(0x0) == '0');
+}
+
+static void test_unhexchar(void) {
+ assert_se(unhexchar('a') == 0xA);
+ assert_se(unhexchar('A') == 0xA);
+ assert_se(unhexchar('0') == 0x0);
+}
+
+static void test_octchar(void) {
+ assert_se(octchar(00) == '0');
+ assert_se(octchar(07) == '7');
+}
+
+static void test_unoctchar(void) {
+ assert_se(unoctchar('0') == 00);
+ assert_se(unoctchar('7') == 07);
+}
+
+static void test_decchar(void) {
+ assert_se(decchar(0) == '0');
+ assert_se(decchar(9) == '9');
+}
+
+static void test_undecchar(void) {
+ assert_se(undecchar('0') == 0);
+ assert_se(undecchar('9') == 9);
+}
+
+static void test_foreach_word(void) {
+ char *w, *state;
+ size_t l;
+ int i = 0;
+ const char test[] = "test abc d\te f ";
+ const char * const expected[] = {
+ "test",
+ "abc",
+ "d",
+ "e",
+ "f",
+ "",
+ NULL
+ };
+
+ FOREACH_WORD(w, l, test, state) {
+ assert_se(strneq(expected[i++], w, l));
+ }
+}
+
+static void test_foreach_word_quoted(void) {
+ char *w, *state;
+ size_t l;
+ int i = 0;
+ const char test[] = "test a b c 'd' e '' '' hhh '' '' \"a b c\"";
+ const char * const expected[] = {
+ "test",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "",
+ "",
+ "hhh",
+ "",
+ "",
+ "a b c",
+ NULL
+ };
+
+ printf("<%s>\n", test);
+ FOREACH_WORD_QUOTED(w, l, test, state) {
+ _cleanup_free_ char *t = NULL;
+
+ assert_se(t = strndup(w, l));
+ assert_se(strneq(expected[i++], w, l));
+ printf("<%s>\n", t);
+ }
+}
+
+static void test_default_term_for_tty(void) {
+ puts(default_term_for_tty("/dev/tty23"));
+ puts(default_term_for_tty("/dev/ttyS23"));
+ puts(default_term_for_tty("/dev/tty0"));
+ puts(default_term_for_tty("/dev/pty0"));
+ puts(default_term_for_tty("/dev/pts/0"));
+ puts(default_term_for_tty("/dev/console"));
+ puts(default_term_for_tty("tty23"));
+ puts(default_term_for_tty("ttyS23"));
+ puts(default_term_for_tty("tty0"));
+ puts(default_term_for_tty("pty0"));
+ puts(default_term_for_tty("pts/0"));
+ puts(default_term_for_tty("console"));
+}
+
+static void test_memdup_multiply(void) {
+ int org[] = {1, 2, 3};
+ int *dup;
+
+ dup = (int*)memdup_multiply(org, sizeof(int), 3);
+
+ assert_se(dup);
+ assert_se(dup[0] == 1);
+ assert_se(dup[1] == 2);
+ assert_se(dup[2] == 3);
+ free(dup);
+}
+
+static void test_bus_path_escape_one(const char *a, const char *b) {
+ _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
+
+ assert_se(t = bus_path_escape(a));
+ assert_se(streq(t, b));
+
+ assert_se(x = bus_path_unescape(t));
+ assert_se(streq(a, x));
+
+ assert_se(y = bus_path_unescape(b));
+ assert_se(streq(a, y));
+}
+
+static void test_bus_path_escape(void) {
+ test_bus_path_escape_one("foo123bar", "foo123bar");
+ test_bus_path_escape_one("foo.bar", "foo_2ebar");
+ test_bus_path_escape_one("foo_2ebar", "foo_5f2ebar");
+ test_bus_path_escape_one("", "_");
+ test_bus_path_escape_one("_", "_5f");
+ test_bus_path_escape_one("1", "_31");
+ test_bus_path_escape_one(":1", "_3a1");
+}
+
+static void test_hostname_is_valid(void) {
+ assert(hostname_is_valid("foobar"));
+ assert(hostname_is_valid("foobar.com"));
+ assert(!hostname_is_valid("fööbar"));
+ assert(!hostname_is_valid(""));
+ assert(!hostname_is_valid("."));
+ assert(!hostname_is_valid(".."));
+ assert(!hostname_is_valid("foobar."));
+ assert(!hostname_is_valid(".foobar"));
+ assert(!hostname_is_valid("foo..bar"));
+ assert(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
+}
+
+static void test_u64log2(void) {
+ assert(u64log2(0) == 0);
+ assert(u64log2(8) == 3);
+ assert(u64log2(9) == 3);
+ assert(u64log2(15) == 3);
+ assert(u64log2(16) == 4);
+ assert(u64log2(1024*1024) == 20);
+ assert(u64log2(1024*1024+5) == 20);
+}
+
+static void test_get_process_comm(void) {
+ _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
+ unsigned long long b;
+ pid_t e;
+ uid_t u;
+ gid_t g;
+ dev_t h;
+ int r;
+
+ assert_se(get_process_comm(1, &a) >= 0);
+ log_info("pid1 comm: '%s'", a);
+
+ assert_se(get_starttime_of_pid(1, &b) >= 0);
+ log_info("pid1 starttime: '%llu'", b);
+
+ assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
+ log_info("pid1 cmdline: '%s'", c);
+
+ assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
+ log_info("pid1 cmdline truncated: '%s'", d);
+
+ assert_se(get_parent_of_pid(1, &e) >= 0);
+ log_info("pid1 ppid: '%llu'", (unsigned long long) e);
+ assert_se(e == 0);
+
+ assert_se(is_kernel_thread(1) == 0);
+
+ r = get_process_exe(1, &f);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("pid1 exe: '%s'", strna(f));
+
+ assert_se(get_process_uid(1, &u) == 0);
+ log_info("pid1 uid: '%llu'", (unsigned long long) u);
+ assert_se(u == 0);
+
+ assert_se(get_process_gid(1, &g) == 0);
+ log_info("pid1 gid: '%llu'", (unsigned long long) g);
+ assert_se(g == 0);
+
+ assert(get_ctty_devnr(1, &h) == -ENOENT);
+
+ getenv_for_pid(1, "PATH", &i);
+ log_info("pid1 $PATH: '%s'", strna(i));
+}
+
+static void test_protect_errno(void) {
+ errno = 12;
+ {
+ PROTECT_ERRNO;
+ errno = 11;
+ }
+ assert(errno == 12);
+}
+
+int main(int argc, char *argv[]) {
+ test_streq_ptr();
+ test_first_word();
+ test_close_many();
+ test_parse_boolean();
+ test_parse_pid();
+ test_parse_uid();
+ test_safe_atolli();
+ test_safe_atod();
+ test_strappend();
+ test_strstrip();
+ test_delete_chars();
+ test_in_charset();
+ test_hexchar();
+ test_unhexchar();
+ test_octchar();
+ test_unoctchar();
+ test_decchar();
+ test_undecchar();
+ test_foreach_word();
+ test_foreach_word_quoted();
+ test_default_term_for_tty();
+ test_memdup_multiply();
+ test_bus_path_escape();
+ test_hostname_is_valid();
+ test_u64log2();
+ test_get_process_comm();
+ test_protect_errno();
+
+ return 0;
+}
diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c
new file mode 100644
index 0000000000..ccb1854708
--- /dev/null
+++ b/src/test/test-watchdog.c
@@ -0,0 +1,51 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <string.h>
+
+#include "watchdog.h"
+#include "log.h"
+
+int main(int argc, char *argv[]) {
+ usec_t t = 10 * USEC_PER_SEC;
+ unsigned i;
+ int r;
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+
+ r = watchdog_set_timeout(&t);
+ if (r < 0)
+ log_warning("Failed to open watchdog: %s", strerror(-r));
+
+ for (i = 0; i < 5; i++) {
+ log_info("Pinging...");
+ r = watchdog_ping();
+ if (r < 0)
+ log_warning("Failed to ping watchdog: %s", strerror(-r));
+
+ usleep(t/2);
+ }
+
+ watchdog_close(true);
+ return 0;
+}