summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backlight/backlight.c2
-rw-r--r--src/basic/cpu-set-util.c1
-rw-r--r--src/basic/def.h24
-rw-r--r--src/basic/escape.c1
-rw-r--r--src/basic/extract-word.c3
-rw-r--r--src/basic/glob-util.c1
-rw-r--r--src/basic/glob-util.h2
-rw-r--r--src/basic/macro.h15
-rw-r--r--src/basic/parse-util.c13
-rw-r--r--src/basic/parse-util.h1
-rw-r--r--src/basic/proc-cmdline.c31
-rw-r--r--src/basic/proc-cmdline.h1
-rw-r--r--src/basic/replace-var.c4
-rw-r--r--src/basic/string-util.c33
-rw-r--r--src/basic/string-util.h16
-rw-r--r--src/basic/time-util.c14
-rw-r--r--src/basic/time-util.h2
-rw-r--r--src/basic/util.h7
-rw-r--r--src/binfmt/binfmt.c1
-rw-r--r--src/bootchart/bootchart.c1
-rw-r--r--src/core/dbus-execute.c35
-rw-r--r--src/core/dbus-service.c3
-rw-r--r--src/core/load-fragment.c8
-rw-r--r--src/core/main.c91
-rw-r--r--src/debug-generator/debug-generator.c28
-rw-r--r--src/journal-remote/journal-remote.c1
-rw-r--r--src/journal-remote/journal-upload.c1
-rwxr-xr-xsrc/journal-remote/log-generator.py10
-rw-r--r--src/journal/journal-file.c2
-rw-r--r--src/journal/journal-internal.h2
-rw-r--r--src/journal/journalctl.c32
-rw-r--r--src/journal/journald-server.c62
-rw-r--r--src/journal/journald-server.h13
-rw-r--r--src/journal/sd-journal.c296
-rw-r--r--src/libsystemd-network/dhcp6-option.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c3
-rw-r--r--src/libsystemd-network/sd-pppoe.c813
-rw-r--r--src/libsystemd-network/test-pppoe.c177
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c17
-rw-r--r--src/libsystemd/sd-device/sd-device.c9
-rw-r--r--src/libsystemd/sd-login/sd-login.c4
-rw-r--r--src/login/logind.c1
-rw-r--r--src/machine/machine.c13
-rw-r--r--src/modules-load/modules-load.c1
-rw-r--r--src/network/networkctl.c2
-rw-r--r--src/network/networkd-address.c44
-rw-r--r--src/network/networkd-address.h1
-rw-r--r--src/network/networkd-dhcp4.c34
-rw-r--r--src/network/networkd-ipv4ll.c12
-rw-r--r--src/network/networkd-link-bus.c2
-rw-r--r--src/network/networkd-link.c288
-rw-r--r--src/network/networkd-link.h2
-rw-r--r--src/network/networkd-manager.c235
-rw-r--r--src/network/networkd-netdev-bridge.c7
-rw-r--r--src/network/networkd-network.c8
-rw-r--r--src/network/networkd-route.c264
-rw-r--r--src/network/networkd-route.h24
-rw-r--r--src/network/networkd.c6
-rw-r--r--src/network/networkd.h2
-rw-r--r--src/resolve-host/resolve-host.c5
-rw-r--r--src/resolve/resolved-conf.c1
-rw-r--r--src/rfkill/rfkill.c2
-rw-r--r--src/shared/bus-util.c36
-rw-r--r--src/shared/sleep-config.c3
-rw-r--r--src/sysctl/sysctl.c1
-rw-r--r--src/systemctl/systemctl.c54
-rw-r--r--src/systemd/sd-pppoe.h55
-rw-r--r--src/sysusers/sysusers.c5
-rw-r--r--src/sysv-generator/sysv-generator.c2
-rw-r--r--src/test/test-execute.c51
-rw-r--r--src/test/test-path.c2
-rw-r--r--src/test/test-string-util.c61
-rw-r--r--src/test/test-util.c8
-rw-r--r--src/timesync/timesyncd-conf.c5
-rw-r--r--src/tmpfiles/tmpfiles.c1
75 files changed, 1547 insertions, 1473 deletions
diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c
index 08980fba82..b0fa079fec 100644
--- a/src/backlight/backlight.c
+++ b/src/backlight/backlight.c
@@ -381,7 +381,7 @@ int main(int argc, char *argv[]) {
_cleanup_free_ char *value = NULL;
const char *clamp;
- if (!shall_restore_state())
+ if (shall_restore_state() == 0)
return EXIT_SUCCESS;
if (!validate_device(udev, device))
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 4950c66767..e2ec4ca83f 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -24,6 +24,7 @@
#include "cpu-set-util.h"
#include "extract-word.h"
#include "parse-util.h"
+#include "string-util.h"
#include "util.h"
cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
diff --git a/src/basic/def.h b/src/basic/def.h
index 7c4161eb72..950f693899 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -35,17 +35,14 @@
* the watchdog pings will keep the loop busy. */
#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
+/* The default value for the net.unix.max_dgram_qlen sysctl */
+#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL
+
#define SYSTEMD_CGROUP_CONTROLLER "name=systemd"
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
-#define DIGITS "0123456789"
-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
-#define ALPHANUMERICAL LETTERS DIGITS
-
#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
#ifdef HAVE_SPLIT_USR
@@ -78,3 +75,18 @@
#define NOTIFY_FD_MAX 768
#define NOTIFY_BUFFER_MAX PIPE_BUF
+
+/* Return a nulstr for a standard cascade of configuration directories,
+ * suitable to pass to conf_files_list_nulstr or config_parse_many. */
+#define CONF_DIRS_NULSTR(n) \
+ "/etc/" n ".d\0" \
+ "/run/" n ".d\0" \
+ "/usr/local/lib/" n ".d\0" \
+ "/usr/lib/" n ".d\0" \
+ CONF_DIR_SPLIT_USR(n)
+
+#ifdef HAVE_SPLIT_USR
+#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
+#else
+#define CONF_DIR_SPLIT_USR(n)
+#endif
diff --git a/src/basic/escape.c b/src/basic/escape.c
index add0d7795b..4815161b09 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -22,6 +22,7 @@
#include "alloc-util.h"
#include "escape.h"
#include "hexdecoct.h"
+#include "string-util.h"
#include "utf8.h"
#include "util.h"
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index c0f9394fad..6721b85c0a 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -21,9 +21,10 @@
#include "alloc-util.h"
#include "escape.h"
+#include "extract-word.h"
+#include "string-util.h"
#include "utf8.h"
#include "util.h"
-#include "extract-word.h"
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
_cleanup_free_ char *s = NULL;
diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c
index 112c6392e5..0bfbcb1d37 100644
--- a/src/basic/glob-util.c
+++ b/src/basic/glob-util.c
@@ -22,6 +22,7 @@
#include <glob.h>
#include "glob-util.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h
index 8817df14b4..793adf4a6c 100644
--- a/src/basic/glob-util.h
+++ b/src/basic/glob-util.h
@@ -24,7 +24,7 @@
#include <string.h>
#include "macro.h"
-#include "util.h"
+#include "string-util.h"
int glob_exists(const char *path);
int glob_extend(char ***strv, const char *path);
diff --git a/src/basic/macro.h b/src/basic/macro.h
index daa7c416f7..5088e6720d 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -334,21 +334,6 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
_found; \
})
-/* Return a nulstr for a standard cascade of configuration directories,
- * suitable to pass to conf_files_list_nulstr or config_parse_many. */
-#define CONF_DIRS_NULSTR(n) \
- "/etc/" n ".d\0" \
- "/run/" n ".d\0" \
- "/usr/local/lib/" n ".d\0" \
- "/usr/lib/" n ".d\0" \
- CONF_DIR_SPLIT_USR(n)
-
-#ifdef HAVE_SPLIT_USR
-#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
-#else
-#define CONF_DIR_SPLIT_USR(n)
-#endif
-
/* Define C11 thread_local attribute even on older gcc compiler
* version */
#ifndef thread_local
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 1ee5783680..b6358c459a 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -81,6 +81,19 @@ int parse_mode(const char *s, mode_t *ret) {
return 0;
}
+int parse_ifindex(const char *s, int *ret) {
+ int ifi, r;
+
+ r = safe_atoi(s, &ifi);
+ if (r < 0)
+ return r;
+ if (ifi <= 0)
+ return -EINVAL;
+
+ *ret = ifi;
+ return 0;
+}
+
int parse_size(const char *t, uint64_t base, uint64_t *size) {
/* Soo, sometimes we want to parse IEC binary suffixes, and
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 0e56848e26..408690d0b3 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -31,6 +31,7 @@
int parse_boolean(const char *v) _pure_;
int parse_pid(const char *s, pid_t* ret_pid);
int parse_mode(const char *s, mode_t *ret);
+int parse_ifindex(const char *s, int *ret);
int parse_size(const char *t, uint64_t base, uint64_t *size);
int parse_range(const char *t, unsigned *lower, unsigned *upper);
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c
index dd91ce7dbc..4464573c5b 100644
--- a/src/basic/proc-cmdline.c
+++ b/src/basic/proc-cmdline.c
@@ -26,6 +26,7 @@
#include "parse-util.h"
#include "proc-cmdline.h"
#include "process-util.h"
+#include "special.h"
#include "string-util.h"
#include "util.h"
#include "virt.h"
@@ -141,5 +142,33 @@ int shall_restore_state(void) {
if (r == 0)
return true;
- return parse_boolean(value) != 0;
+ return parse_boolean(value);
+}
+
+static const char * const rlmap[] = {
+ "emergency", SPECIAL_EMERGENCY_TARGET,
+ "-b", SPECIAL_EMERGENCY_TARGET,
+ "rescue", SPECIAL_RESCUE_TARGET,
+ "single", SPECIAL_RESCUE_TARGET,
+ "-s", SPECIAL_RESCUE_TARGET,
+ "s", SPECIAL_RESCUE_TARGET,
+ "S", SPECIAL_RESCUE_TARGET,
+ "1", SPECIAL_RESCUE_TARGET,
+ "2", SPECIAL_MULTI_USER_TARGET,
+ "3", SPECIAL_MULTI_USER_TARGET,
+ "4", SPECIAL_MULTI_USER_TARGET,
+ "5", SPECIAL_GRAPHICAL_TARGET,
+};
+
+const char* runlevel_to_target(const char *word) {
+ size_t i;
+
+ if (!word)
+ return NULL;
+
+ for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
+ if (streq(word, rlmap[i]))
+ return rlmap[i+1];
+
+ return NULL;
}
diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h
index ea8277b053..ce6e84995a 100644
--- a/src/basic/proc-cmdline.h
+++ b/src/basic/proc-cmdline.h
@@ -26,3 +26,4 @@ int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
int get_proc_cmdline_key(const char *parameter, char **value);
int shall_restore_state(void);
+const char* runlevel_to_target(const char *rl);
diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c
index 18b49a9227..bf757cbc48 100644
--- a/src/basic/replace-var.c
+++ b/src/basic/replace-var.c
@@ -23,9 +23,9 @@
#include "alloc-util.h"
#include "macro.h"
-#include "util.h"
#include "replace-var.h"
-#include "def.h"
+#include "string-util.h"
+#include "util.h"
/*
* Generic infrastructure for replacing @FOO@ style variables in
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 63b9b79df9..6006767daa 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -21,9 +21,9 @@
#include "alloc-util.h"
#include "gunicode.h"
+#include "string-util.h"
#include "utf8.h"
#include "util.h"
-#include "string-util.h"
int strcmp_ptr(const char *a, const char *b) {
@@ -748,23 +748,38 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
-void string_erase(char *x) {
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+
+void* memory_erase(void *p, size_t l) {
+ volatile uint8_t* x = (volatile uint8_t*) p;
+
+ /* This basically does what memset() does, but hopefully isn't
+ * optimized away by the compiler. One of those days, when
+ * glibc learns memset_s() we should replace this call by
+ * memset_s(), but until then this has to do. */
+
+ for (; l > 0; l--)
+ *(x++) = 'x';
+
+ return p;
+}
+
+#pragma GCC pop_options
+
+char* string_erase(char *x) {
if (!x)
- return;
+ return NULL;
/* A delicious drop of snake-oil! To be called on memory where
* we stored passphrases or so, after we used them. */
- memory_erase(x, strlen(x));
+ return memory_erase(x, strlen(x));
}
char *string_free_erase(char *s) {
- if (!s)
- return NULL;
-
- string_erase(s);
- return mfree(s);
+ return mfree(string_erase(s));
}
bool string_is_safe(const char *p) {
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index 297b8f8232..54f9d3058c 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -26,6 +26,18 @@
#include "macro.h"
+/* What is interpreted as whitespace? */
+#define WHITESPACE " \t\n\r"
+#define NEWLINE "\n\r"
+#define QUOTES "\"\'"
+#define COMMENTS "#;"
+#define GLOB_CHARS "*?["
+#define DIGITS "0123456789"
+#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
+#define ALPHANUMERICAL LETTERS DIGITS
+
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
@@ -162,8 +174,8 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const
return memmem(haystack, haystacklen, needle, needlelen);
}
-#define memory_erase(p, l) memset((p), 'x', (l))
-void string_erase(char *x);
+void* memory_erase(void *p, size_t l);
+char *string_erase(char *x);
char *string_free_erase(char *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 9dc280efc6..e629d91cb2 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -1122,3 +1122,17 @@ time_t mktime_or_timegm(struct tm *tm, bool utc) {
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
}
+
+unsigned long usec_to_jiffies(usec_t u) {
+ static thread_local unsigned long hz = 0;
+ long r;
+
+ if (hz == 0) {
+ r = sysconf(_SC_CLK_TCK);
+
+ assert(r > 0);
+ hz = (unsigned long) r;
+ }
+
+ return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
+}
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 417376ea96..925bf18eb2 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -121,3 +121,5 @@ int get_timezone(char **timezone);
time_t mktime_or_timegm(struct tm *tm, bool utc);
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
+
+unsigned long usec_to_jiffies(usec_t usec);
diff --git a/src/basic/util.h b/src/basic/util.h
index a8fba372d1..d9d2f72b75 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -44,13 +44,6 @@
#include "missing.h"
#include "time-util.h"
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n\r"
-#define NEWLINE "\n\r"
-#define QUOTES "\"\'"
-#define COMMENTS "#;"
-#define GLOB_CHARS "*?["
-
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 8e63153c92..594c9ebe43 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -29,6 +29,7 @@
#include "alloc-util.h"
#include "conf-files.h"
+#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 6723fa5098..852febb225 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -51,6 +51,7 @@
#include "alloc-util.h"
#include "bootchart.h"
#include "conf-parser.h"
+#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "io-util.h"
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 04a5a22b72..db4206a523 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1391,6 +1391,41 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "RuntimeDirectory")) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ if (!filename_is_valid(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
+ }
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (strv_isempty(l)) {
+ c->runtime_directory = strv_free(c->runtime_directory);
+ unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ } else {
+ r = strv_extend_strv(&c->runtime_directory, l, true);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join_quoted(c->runtime_directory);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ }
+ }
+
+ return 1;
+
} else if (rlimit_from_string(name) >= 0) {
uint64_t rl;
rlim_t x;
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index c41b3e1723..24f611a593 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -63,7 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0),
SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index a30cd0967d..5949749374 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3232,12 +3232,14 @@ int config_parse_namespace_path_strv(
int offset;
r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring: %s", prev);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
return 0;
}
- if (r == 0)
- break;
if (!utf8_is_valid(word)) {
log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
diff --git a/src/core/main.c b/src/core/main.c
index 593b974566..696372e37c 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -301,20 +301,6 @@ static int parse_crash_chvt(const char *value) {
static int parse_proc_cmdline_item(const char *key, const char *value) {
- static const char * const rlmap[] = {
- "emergency", SPECIAL_EMERGENCY_TARGET,
- "-b", SPECIAL_EMERGENCY_TARGET,
- "rescue", SPECIAL_RESCUE_TARGET,
- "single", SPECIAL_RESCUE_TARGET,
- "-s", SPECIAL_RESCUE_TARGET,
- "s", SPECIAL_RESCUE_TARGET,
- "S", SPECIAL_RESCUE_TARGET,
- "1", SPECIAL_RESCUE_TARGET,
- "2", SPECIAL_MULTI_USER_TARGET,
- "3", SPECIAL_MULTI_USER_TARGET,
- "4", SPECIAL_MULTI_USER_TARGET,
- "5", SPECIAL_GRAPHICAL_TARGET,
- };
int r;
assert(key);
@@ -415,12 +401,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
log_set_target(LOG_TARGET_CONSOLE);
} else if (!in_initrd() && !value) {
- unsigned i;
+ const char *target;
/* SysV compatibility */
- for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
- if (streq(key, rlmap[i]))
- return free_and_strdup(&arg_default_unit, rlmap[i+1]);
+ target = runlevel_to_target(key);
+ if (target)
+ return free_and_strdup(&arg_default_unit, target);
}
return 0;
@@ -1113,33 +1099,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
return 0;
}
-static void test_mtab(void) {
-
- static const char ok[] =
- "/proc/self/mounts\0"
- "/proc/mounts\0"
- "../proc/self/mounts\0"
- "../proc/mounts\0";
-
- _cleanup_free_ char *p = NULL;
- int r;
-
- /* Check that /etc/mtab is a symlink to the right place or
- * non-existing. But certainly not a file, or a symlink to
- * some weird place... */
-
- r = readlink_malloc("/etc/mtab", &p);
- if (r == -ENOENT)
- return;
- if (r >= 0 && nulstr_contains(ok, p))
- return;
-
- log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
- "This is not supported anymore. "
- "Please replace /etc/mtab with a symlink to /proc/self/mounts.");
- freeze_or_reboot();
-}
-
static void test_usr(void) {
/* Check that /usr is not a separate fs */
@@ -1242,12 +1201,50 @@ static int status_welcome(void) {
static int write_container_id(void) {
const char *c;
+ int r;
c = getenv("container");
if (isempty(c))
return 0;
- return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
+
+ return 1;
+}
+
+static int bump_unix_max_dgram_qlen(void) {
+ _cleanup_free_ char *qlen = NULL;
+ unsigned long v;
+ int r;
+
+ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel
+ * default of 16 is simply too low. We set the value really
+ * really early during boot, so that it is actually applied to
+ * all our sockets, including the $NOTIFY_SOCKET one. */
+
+ r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m");
+
+ r = safe_atolu(qlen, &v);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m");
+
+ if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
+ return 0;
+
+ qlen = mfree(qlen);
+ if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0)
+ return log_oom();
+
+ r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0);
+ if (r < 0)
+ return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to bump AF_UNIX datagram queue length, ignoring: %m");
+
+ return 1;
}
int main(int argc, char *argv[]) {
@@ -1613,8 +1610,8 @@ int main(int argc, char *argv[]) {
hostname_setup();
machine_id_setup(NULL);
loopback_setup();
+ bump_unix_max_dgram_qlen();
- test_mtab();
test_usr();
}
diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c
index e16c3b9453..413cfd0388 100644
--- a/src/debug-generator/debug-generator.c
+++ b/src/debug-generator/debug-generator.c
@@ -23,11 +23,13 @@
#include "mkdir.h"
#include "parse-util.h"
#include "proc-cmdline.h"
+#include "special.h"
#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "util.h"
+static char *arg_default_unit = NULL;
static const char *arg_dest = "/tmp";
static char **arg_mask = NULL;
static char **arg_wants = NULL;
@@ -80,6 +82,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
arg_debug_shell = r;
} else
arg_debug_shell = true;
+ } else if (streq(key, "systemd.unit")) {
+
+ if (!value)
+ log_error("Missing argument for systemd.unit= kernel command line parameter.");
+ else {
+ r = free_and_strdup(&arg_default_unit, value);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default unit %s: %m", value);
+ }
+ } else if (!value) {
+ const char *target;
+
+ target = runlevel_to_target(key);
+ if (target) {
+ r = free_and_strdup(&arg_default_unit, target);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default unit %s: %m", target);
+ }
}
return 0;
@@ -118,7 +138,7 @@ static int generate_wants_symlinks(void) {
STRV_FOREACH(u, arg_wants) {
_cleanup_free_ char *p = NULL, *f = NULL;
- p = strjoin(arg_dest, "/default.target.wants/", *u, NULL);
+ p = strjoin(arg_dest, "/", arg_default_unit, ".wants/", *u, NULL);
if (!p)
return log_oom();
@@ -154,6 +174,12 @@ int main(int argc, char *argv[]) {
umask(0022);
+ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
+ goto finish;
+ }
+
r = parse_proc_cmdline(parse_proc_cmdline_item);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index dc69bb8679..6326f902e8 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -37,6 +37,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "def.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 7d274d2fc9..42d14dc7c4 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -29,6 +29,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
diff --git a/src/journal-remote/log-generator.py b/src/journal-remote/log-generator.py
index 9a8fb07c7f..fd6964e758 100755
--- a/src/journal-remote/log-generator.py
+++ b/src/journal-remote/log-generator.py
@@ -6,6 +6,8 @@ import argparse
PARSER = argparse.ArgumentParser()
PARSER.add_argument('n', type=int)
PARSER.add_argument('--dots', action='store_true')
+PARSER.add_argument('--data-size', type=int, default=4000)
+PARSER.add_argument('--data-type', choices={'random', 'simple'})
OPTIONS = PARSER.parse_args()
template = """\
@@ -38,10 +40,16 @@ facility = 6
src = open('/dev/urandom', 'rb')
bytes = 0
+counter = 0
for i in range(OPTIONS.n):
message = repr(src.read(2000))
- data = repr(src.read(4000))
+ if OPTIONS.data_type == 'random':
+ data = repr(src.read(OPTIONS.data_size))
+ else:
+ # keep the pattern non-repeating so we get a different blob every time
+ data = '{:0{}}'.format(counter, OPTIONS.data_size)
+ counter += 1
entry = template.format(m=m,
realtime_ts=realtime_ts,
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 12b39dbb27..e00a0d711d 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2705,7 +2705,7 @@ int journal_file_open(
}
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
- r = -EIO;
+ r = -ENODATA;
goto fail;
}
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index 1221799c1d..06847402e0 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -121,7 +121,7 @@ struct sd_journal {
Hashmap *directories_by_path;
Hashmap *directories_by_wd;
- Set *errors;
+ Hashmap *errors;
};
char *journal_make_match_string(sd_journal *j);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index a35783e3ff..98a852cb50 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -1708,36 +1708,50 @@ static int access_check_var_log_journal(sd_journal *j) {
static int access_check(sd_journal *j) {
Iterator it;
void *code;
+ char *path;
int r = 0;
assert(j);
- if (set_isempty(j->errors)) {
+ if (hashmap_isempty(j->errors)) {
if (ordered_hashmap_isempty(j->files))
log_notice("No journal files were found.");
return 0;
}
- if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
+ if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) {
(void) access_check_var_log_journal(j);
if (ordered_hashmap_isempty(j->files))
r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
}
- SET_FOREACH(code, j->errors, it) {
+ HASHMAP_FOREACH_KEY(path, code, j->errors, it) {
int err;
- err = -PTR_TO_INT(code);
- assert(err > 0);
+ err = abs(PTR_TO_INT(code));
- if (err == EACCES)
+ switch (err) {
+ case EACCES:
continue;
- log_warning_errno(err, "Error was encountered while opening journal files: %m");
- if (r == 0)
- r = -err;
+ case ENODATA:
+ log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
+ break;
+
+ case EPROTONOSUPPORT:
+ log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path);
+ break;
+
+ case EBADMSG:
+ log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
+ break;
+
+ default:
+ log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
+ break;
+ }
}
return r;
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 299b0a848f..3fd25d1af4 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1473,10 +1473,10 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents,
}
/* The $NOTIFY_SOCKET is writable again, now send exactly one
- * message on it. Either it's the initial READY=1 event or an
- * stdout stream event. If there's nothing to write anymore,
- * turn our event source off. The next time there's something
- * to send it will be turned on again. */
+ * message on it. Either it's the wtachdog event, the initial
+ * READY=1 event or an stdout stream event. If there's nothing
+ * to write anymore, turn our event source off. The next time
+ * there's something to send it will be turned on again. */
if (!s->sent_notify_ready) {
static const char p[] =
@@ -1495,12 +1495,30 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents,
s->sent_notify_ready = true;
log_debug("Sent READY=1 notification.");
+ } else if (s->send_watchdog) {
+
+ static const char p[] =
+ "WATCHDOG=1";
+
+ ssize_t l;
+
+ l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m");
+ }
+
+ s->send_watchdog = false;
+ log_debug("Sent WATCHDOG=1 notification.");
+
} else if (s->stdout_streams_notify_queue)
/* Dispatch one stream notification event */
stdout_stream_send_notify(s->stdout_streams_notify_queue);
/* Leave us enabled if there's still more to to do. */
- if (s->stdout_streams_notify_queue)
+ if (s->send_watchdog || s->stdout_streams_notify_queue)
return 0;
/* There was nothing to do anymore, let's turn ourselves off. */
@@ -1511,6 +1529,29 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents,
return 0;
}
+static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) {
+ Server *s = userdata;
+ int r;
+
+ assert(s);
+
+ s->send_watchdog = true;
+
+ r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON);
+ if (r < 0)
+ log_warning_errno(r, "Failed to turn on notify event source: %m");
+
+ r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2);
+ if (r < 0)
+ return log_error_errno(r, "Failed to restart watchdog event source: %m");
+
+ r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable watchdog event source: %m");
+
+ return 0;
+}
+
static int server_connect_notify(Server *s) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
@@ -1573,6 +1614,14 @@ static int server_connect_notify(Server *s) {
if (r < 0)
return log_error_errno(r, "Failed to watch notification socket: %m");
+ if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) {
+ s->send_watchdog = true;
+
+ r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec*3/4, dispatch_watchdog, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add watchdog time event: %m");
+ }
+
/* This should fire pretty soon, which we'll use to send the
* READY=1 event. */
@@ -1591,6 +1640,8 @@ int server_init(Server *s) {
s->compress = true;
s->seal = true;
+ s->watchdog_usec = USEC_INFINITY;
+
s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
s->sync_scheduled = false;
@@ -1808,6 +1859,7 @@ void server_done(Server *s) {
sd_event_source_unref(s->sigint_event_source);
sd_event_source_unref(s->hostname_event_source);
sd_event_source_unref(s->notify_event_source);
+ sd_event_source_unref(s->watchdog_event_source);
sd_event_unref(s->event);
safe_close(s->syslog_fd);
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index 170602ea16..03a61bd2ed 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -74,6 +74,7 @@ struct Server {
sd_event_source *sigint_event_source;
sd_event_source *hostname_event_source;
sd_event_source *notify_event_source;
+ sd_event_source *watchdog_event_source;
JournalFile *runtime_journal;
JournalFile *system_journal;
@@ -130,14 +131,14 @@ struct Server {
MMapCache *mmap;
- bool dev_kmsg_readable;
+ struct udev *udev;
uint64_t *kernel_seqnum;
+ bool dev_kmsg_readable:1;
- struct udev *udev;
-
- bool sent_notify_ready;
- bool sync_scheduled;
+ bool send_watchdog:1;
+ bool sent_notify_ready:1;
+ bool sync_scheduled:1;
char machine_id_field[sizeof("_MACHINE_ID=") + 32];
char boot_id_field[sizeof("_BOOT_ID=") + 32];
@@ -145,6 +146,8 @@ struct Server {
/* Cached cgroup root, so that we don't have to query that all the time */
char *cgroup_root;
+
+ usec_t watchdog_usec;
};
#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 218df8cebe..5cde7f17f7 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -73,19 +73,46 @@ static bool journal_pid_changed(sd_journal *j) {
return j->original_pid != getpid();
}
-/* We return an error here only if we didn't manage to
- memorize the real error. */
-static int set_put_error(sd_journal *j, int r) {
+static int journal_put_error(sd_journal *j, int r, const char *path) {
+ char *copy;
int k;
+ /* Memorize an error we encountered, and store which
+ * file/directory it was generated from. Note that we store
+ * only *one* path per error code, as the error code is the
+ * key into the hashmap, and the path is the value. This means
+ * we keep track only of all error kinds, but not of all error
+ * locations. This has the benefit that the hashmap cannot
+ * grow beyond bounds.
+ *
+ * We return an error here only if we didn't manage to
+ * memorize the real error. */
+
if (r >= 0)
return r;
- k = set_ensure_allocated(&j->errors, NULL);
+ k = hashmap_ensure_allocated(&j->errors, NULL);
if (k < 0)
return k;
- return set_put(j->errors, INT_TO_PTR(r));
+ if (path) {
+ copy = strdup(path);
+ if (!copy)
+ return -ENOMEM;
+ } else
+ copy = NULL;
+
+ k = hashmap_put(j->errors, INT_TO_PTR(r), copy);
+ if (k < 0) {
+ free(copy);
+
+ if (k == -EEXIST)
+ return 0;
+
+ return k;
+ }
+
+ return 0;
}
static void detach_location(sd_journal *j) {
@@ -1183,6 +1210,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) {
}
static bool file_type_wanted(int flags, const char *filename) {
+ assert(filename);
+
if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
return false;
@@ -1207,7 +1236,7 @@ static bool file_type_wanted(int flags, const char *filename) {
static int add_any_file(sd_journal *j, const char *path) {
JournalFile *f = NULL;
- int r;
+ int r, k;
assert(j);
assert(path);
@@ -1216,20 +1245,23 @@ static int add_any_file(sd_journal *j, const char *path) {
return 0;
if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
- log_warning("Too many open journal files, not adding %s.", path);
- return set_put_error(j, -ETOOMANYREFS);
+ log_debug("Too many open journal files, not adding %s.", path);
+ r = -ETOOMANYREFS;
+ goto fail;
}
r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
- if (r < 0)
- return r;
+ if (r < 0) {
+ log_debug_errno(r, "Failed to open journal file %s: %m", path);
+ goto fail;
+ }
/* journal_file_dump(f); */
r = ordered_hashmap_put(j->files, f->path, f);
if (r < 0) {
journal_file_close(f);
- return r;
+ goto fail;
}
log_debug("File %s added.", f->path);
@@ -1239,11 +1271,17 @@ static int add_any_file(sd_journal *j, const char *path) {
j->current_invalidate_counter ++;
return 0;
+
+fail:
+ k = journal_put_error(j, r, path);
+ if (k < 0)
+ return k;
+
+ return r;
}
static int add_file(sd_journal *j, const char *prefix, const char *filename) {
- _cleanup_free_ char *path = NULL;
- int r;
+ const char *path;
assert(j);
assert(prefix);
@@ -1253,34 +1291,24 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
!file_type_wanted(j->flags, filename))
return 0;
- path = strjoin(prefix, "/", filename, NULL);
- if (!path)
- return -ENOMEM;
-
- r = add_any_file(j, path);
- if (r == -ENOENT)
- return 0;
- return r;
+ path = strjoina(prefix, "/", filename);
+ return add_any_file(j, path);
}
-static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
- _cleanup_free_ char *path;
+static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
+ const char *path;
JournalFile *f;
assert(j);
assert(prefix);
assert(filename);
- path = strjoin(prefix, "/", filename, NULL);
- if (!path)
- return -ENOMEM;
-
+ path = strjoina(prefix, "/", filename);
f = ordered_hashmap_get(j->files, path);
if (!f)
- return 0;
+ return;
remove_file_real(j, f);
- return 0;
}
static void remove_file_real(sd_journal *j, JournalFile *f) {
@@ -1309,12 +1337,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
j->current_invalidate_counter ++;
}
+static int dirname_is_machine_id(const char *fn) {
+ sd_id128_t id, machine;
+ int r;
+
+ r = sd_id128_get_machine(&machine);
+ if (r < 0)
+ return r;
+
+ r = sd_id128_from_string(fn, &id);
+ if (r < 0)
+ return r;
+
+ return sd_id128_equal(id, machine);
+}
+
static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
_cleanup_free_ char *path = NULL;
- int r;
_cleanup_closedir_ DIR *d = NULL;
- sd_id128_t id, mid;
+ struct dirent *de = NULL;
Directory *m;
+ int r, k;
assert(j);
assert(prefix);
@@ -1323,35 +1366,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
log_debug("Considering %s/%s.", prefix, dirname);
if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
- (sd_id128_from_string(dirname, &id) < 0 ||
- sd_id128_get_machine(&mid) < 0 ||
- !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
+ !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
return 0;
path = strjoin(prefix, "/", dirname, NULL);
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ r = -ENOMEM;
+ goto fail;
+ }
d = opendir(path);
if (!d) {
- log_debug_errno(errno, "Failed to open %s: %m", path);
- if (errno == ENOENT)
- return 0;
- return -errno;
+ r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
+ goto fail;
}
m = hashmap_get(j->directories_by_path, path);
if (!m) {
m = new0(Directory, 1);
- if (!m)
- return -ENOMEM;
+ if (!m) {
+ r = -ENOMEM;
+ goto fail;
+ }
m->is_root = false;
m->path = path;
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
path = NULL; /* avoid freeing in cleanup */
@@ -1373,41 +1417,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
inotify_rm_watch(j->inotify_fd, m->wd);
}
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
- return r;
- }
- if (!de)
- break;
+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
if (dirent_is_file_with_suffix(de, ".journal") ||
- dirent_is_file_with_suffix(de, ".journal~")) {
- r = add_file(j, m->path, de->d_name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- m->path, de->d_name);
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- }
+ dirent_is_file_with_suffix(de, ".journal~"))
+ (void) add_file(j, m->path, de->d_name);
}
check_network(j, dirfd(d));
return 0;
+
+fail:
+ k = journal_put_error(j, r, path ?: dirname);
+ if (k < 0)
+ return k;
+
+ return r;
}
-static int add_root_directory(sd_journal *j, const char *p) {
+static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
Directory *m;
- int r;
+ int r, k;
assert(j);
assert(p);
@@ -1420,26 +1453,35 @@ static int add_root_directory(sd_journal *j, const char *p) {
p = strjoina(j->prefix, p);
d = opendir(p);
- if (!d)
- return -errno;
+ if (!d) {
+ if (errno == ENOENT && missing_ok)
+ return 0;
+
+ r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
+ goto fail;
+ }
m = hashmap_get(j->directories_by_path, p);
if (!m) {
m = new0(Directory, 1);
- if (!m)
- return -ENOMEM;
+ if (!m) {
+ r = -ENOMEM;
+ goto fail;
+ }
m->is_root = true;
m->path = strdup(p);
if (!m->path) {
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m->path);
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
j->current_invalidate_counter ++;
@@ -1462,42 +1504,27 @@ static int add_root_directory(sd_journal *j, const char *p) {
if (j->no_new_files)
return 0;
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
sd_id128_t id;
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
- return r;
- }
- if (!de)
- break;
-
if (dirent_is_file_with_suffix(de, ".journal") ||
- dirent_is_file_with_suffix(de, ".journal~")) {
- r = add_file(j, m->path, de->d_name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- m->path, de->d_name);
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
- sd_id128_from_string(de->d_name, &id) >= 0) {
-
- r = add_directory(j, m->path, de->d_name);
- if (r < 0)
- log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
- }
+ dirent_is_file_with_suffix(de, ".journal~"))
+ (void) add_file(j, m->path, de->d_name);
+ else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) &&
+ sd_id128_from_string(de->d_name, &id) >= 0)
+ (void) add_directory(j, m->path, de->d_name);
}
check_network(j, dirfd(d));
return 0;
+
+fail:
+ k = journal_put_error(j, r, p);
+ if (k < 0)
+ return k;
+
+ return r;
}
static void remove_directory(sd_journal *j, Directory *d) {
@@ -1522,8 +1549,8 @@ static void remove_directory(sd_journal *j, Directory *d) {
}
static int add_search_paths(sd_journal *j) {
- int r;
- const char search_paths[] =
+
+ static const char search_paths[] =
"/run/log/journal\0"
"/var/log/journal\0";
const char *p;
@@ -1533,14 +1560,8 @@ static int add_search_paths(sd_journal *j) {
/* We ignore most errors here, since the idea is to only open
* what's actually accessible, and ignore the rest. */
- NULSTR_FOREACH(p, search_paths) {
- r = add_root_directory(j, p);
- if (r < 0 && r != -ENOENT) {
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- }
+ NULSTR_FOREACH(p, search_paths)
+ (void) add_root_directory(j, p, true);
return 0;
}
@@ -1564,17 +1585,14 @@ static int add_current_paths(sd_journal *j) {
if (!dir)
return -ENOMEM;
- r = add_root_directory(j, dir);
- if (r < 0) {
- set_put_error(j, r);
+ r = add_root_directory(j, dir, true);
+ if (r < 0)
return r;
- }
}
return 0;
}
-
static int allocate_inotify(sd_journal *j) {
assert(j);
@@ -1702,11 +1720,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
if (!j)
return -ENOMEM;
- r = add_root_directory(j, path);
- if (r < 0) {
- set_put_error(j, r);
+ r = add_root_directory(j, path, false);
+ if (r < 0)
goto fail;
- }
*ret = j;
return 0;
@@ -1731,10 +1747,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
STRV_FOREACH(path, paths) {
r = add_any_file(j, *path);
- if (r < 0) {
- log_error_errno(r, "Failed to open %s: %m", *path);
+ if (r < 0)
goto fail;
- }
}
j->no_new_files = true;
@@ -1751,6 +1765,7 @@ fail:
_public_ void sd_journal_close(sd_journal *j) {
Directory *d;
JournalFile *f;
+ char *p;
if (!j)
return;
@@ -1778,10 +1793,13 @@ _public_ void sd_journal_close(sd_journal *j) {
mmap_cache_unref(j->mmap);
}
+ while ((p = hashmap_steal_first(j->errors)))
+ free(p);
+ hashmap_free(j->errors);
+
free(j->path);
free(j->prefix);
free(j->unique_field);
- set_free(j->errors);
free(j);
}
@@ -2074,7 +2092,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
if (j->no_new_files)
r = add_current_paths(j);
else if (j->path)
- r = add_root_directory(j, j->path);
+ r = add_root_directory(j, j->path, true);
else
r = add_search_paths(j);
if (r < 0)
@@ -2121,7 +2139,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
Directory *d;
- int r;
assert(j);
assert(e);
@@ -2137,20 +2154,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for a journal file */
- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
- r = add_file(j, d->path, e->name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- d->path, e->name);
- set_put_error(j, r);
- }
-
- } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
-
- r = remove_file(j, d->path, e->name);
- if (r < 0)
- log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
- }
+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+ (void) add_file(j, d->path, e->name);
+ else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
+ remove_file(j, d->path, e->name);
} else if (!d->is_root && e->len == 0) {
@@ -2163,11 +2170,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for root directory */
- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
- r = add_directory(j, d->path, e->name);
- if (r < 0)
- log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
- }
+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+ (void) add_directory(j, d->path, e->name);
}
return;
@@ -2176,7 +2180,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
if (e->mask & IN_IGNORED)
return;
- log_warning("Unknown inotify event.");
+ log_debug("Unknown inotify event.");
}
static int determine_change(sd_journal *j) {
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index 076bb2dac0..0f46df6a1b 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -344,7 +344,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
int r;
assert_return(optlen > 1, -ENODATA);
- assert_return(optval[optlen] == '\0', -EINVAL);
+ assert_return(optval[optlen - 1] == '\0', -EINVAL);
while (pos < optlen) {
_cleanup_free_ char *ret = NULL;
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index c850538d74..42dd15fc15 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -32,11 +32,12 @@
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
+#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "network-internal.h"
-#include "hexdecoct.h"
#include "parse-util.h"
+#include "string-util.h"
#include "unaligned.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c
deleted file mode 100644
index 045decc46c..0000000000
--- a/src/libsystemd-network/sd-pppoe.c
+++ /dev/null
@@ -1,813 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
-
- 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/>.
-***/
-
-/* See RFC 2516 */
-
-#include <net/if.h>
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-#include <linux/if_pppox.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-ioctl.h>
-
-#include "sd-pppoe.h"
-
-#include "alloc-util.h"
-#include "async.h"
-#include "event-util.h"
-#include "fd-util.h"
-#include "random-util.h"
-#include "socket-util.h"
-#include "sparse-endian.h"
-#include "string-util.h"
-#include "utf8.h"
-#include "util.h"
-
-#define PPPOE_MAX_PACKET_SIZE 1484
-#define PPPOE_MAX_PADR_RESEND 16
-
-/* TODO: move this to socket-util.h without getting into
- * a mess with the includes */
-union sockaddr_union_pppox {
- struct sockaddr sa;
- struct sockaddr_pppox pppox;
-};
-
-typedef enum PPPoEState {
- PPPOE_STATE_INITIALIZING,
- PPPOE_STATE_REQUESTING,
- PPPOE_STATE_RUNNING,
- PPPOE_STATE_STOPPED,
- _PPPOE_STATE_MAX,
- _PPPOE_STATE_INVALID = -1,
-} PPPoEState;
-
-typedef struct PPPoETags {
- char *service_name;
- char *ac_name;
- uint8_t *host_uniq;
- size_t host_uniq_len;
- uint8_t *cookie;
- size_t cookie_len;
-} PPPoETags;
-
-struct sd_pppoe {
- unsigned n_ref;
-
- PPPoEState state;
- uint64_t host_uniq;
-
- int ifindex;
- char *ifname;
-
- sd_event *event;
- int event_priority;
- int fd;
- sd_event_source *io;
- sd_event_source *timeout;
- int padr_resend_count;
-
- char *service_name;
- struct ether_addr peer_mac;
- be16_t session_id;
-
- int pppoe_fd;
- int channel;
-
- sd_pppoe_cb_t cb;
- void *userdata;
-
- PPPoETags tags;
-};
-
-#define PPPOE_PACKET_LENGTH(header) \
- be16toh((header)->length)
-
-#define PPPOE_PACKET_TAIL(packet) \
- (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
-
-#define PPPOE_TAG_LENGTH(tag) \
- be16toh((tag)->tag_len)
-
-#define PPPOE_TAG_TYPE(tag) \
- (tag)->tag_type
-
-#define PPPOE_TAG_NEXT(tag) \
- (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag))
-
-#define PPPOE_TAGS_FOREACH(tag, header) \
- for (tag = (header)->tag; \
- ((uint8_t *)(tag) + sizeof(struct pppoe_tag) < (uint8_t*)PPPOE_PACKET_TAIL(header)) && \
- (PPPOE_TAG_NEXT(tag) <= PPPOE_PACKET_TAIL(header)) && \
- (tag >= (header)->tag) && \
- (PPPOE_TAG_TYPE(tag) != PTT_EOL); \
- tag = PPPOE_TAG_NEXT(tag))
-
-static void pppoe_tags_clear(PPPoETags *tags) {
- free(tags->service_name);
- free(tags->ac_name);
- free(tags->host_uniq);
- free(tags->cookie);
-
- zero(*tags);
-}
-
-int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex) {
- assert_return(ppp, -EINVAL);
- assert_return(ifindex > 0, -EINVAL);
-
- ppp->ifindex = ifindex;
-
- return 0;
-}
-
-int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname) {
- char *name;
-
- assert_return(ppp, -EINVAL);
- assert_return(ifname, -EINVAL);
-
- if (strlen(ifname) > IFNAMSIZ)
- return -EINVAL;
-
- name = strdup(ifname);
- if (!name)
- return -ENOMEM;
-
- free(ppp->ifname);
- ppp->ifname = name;
-
- return 0;
-}
-
-int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name) {
- _cleanup_free_ char *name = NULL;
-
- assert_return(ppp, -EINVAL);
-
- if (service_name) {
- name = strdup(service_name);
- if (!name)
- return -ENOMEM;
- }
-
- free(ppp->service_name);
- ppp->service_name = name;
- name = NULL;
-
- return 0;
-}
-
-int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority) {
- int r;
-
- assert_return(ppp, -EINVAL);
- assert_return(!ppp->event, -EBUSY);
-
- if (event)
- ppp->event = sd_event_ref(event);
- else {
- r = sd_event_default(&ppp->event);
- if (r < 0)
- return r;
- }
-
- ppp->event_priority = priority;
-
- return 0;
-}
-
-int sd_pppoe_detach_event(sd_pppoe *ppp) {
- assert_return(ppp, -EINVAL);
-
- ppp->event = sd_event_unref(ppp->event);
-
- return 0;
-}
-
-sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) {
-
- if (!ppp)
- return NULL;
-
- assert(ppp->n_ref > 0);
- ppp->n_ref++;
-
- return ppp;
-}
-
-sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) {
-
- if (!ppp)
- return NULL;
-
- assert(ppp->n_ref > 0);
- ppp->n_ref--;
-
- if (ppp->n_ref > 0)
- return NULL;
-
- pppoe_tags_clear(&ppp->tags);
- free(ppp->ifname);
- free(ppp->service_name);
- sd_pppoe_stop(ppp);
- sd_pppoe_detach_event(ppp);
-
- free(ppp);
- return NULL;
-}
-
-int sd_pppoe_new (sd_pppoe **ret) {
- sd_pppoe *ppp;
-
- assert_return(ret, -EINVAL);
-
- ppp = new0(sd_pppoe, 1);
- if (!ppp)
- return -ENOMEM;
-
- ppp->n_ref = 1;
- ppp->state = _PPPOE_STATE_INVALID;
- ppp->ifindex = -1;
- ppp->fd = -1;
- ppp->pppoe_fd = -1;
- ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
-
- *ret = ppp;
-
- return 0;
-}
-
-int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel) {
- assert_return(ppp, -EINVAL);
- assert_return(channel, -EINVAL);
- assert_return(ppp->pppoe_fd != -1, -EUNATCH);
- assert_return(ppp->state == PPPOE_STATE_RUNNING, -EUNATCH);
-
- *channel = ppp->channel;
-
- return 0;
-}
-
-int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata) {
- assert_return(ppp, -EINVAL);
-
- ppp->cb = cb;
- ppp->userdata = userdata;
-
- return 0;
-}
-
-static void pppoe_tag_append(struct pppoe_hdr *packet, size_t packet_size, be16_t tag_type, const void *tag_data, uint16_t tag_len) {
- struct pppoe_tag *tag;
-
- assert(packet);
- assert(sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len <= packet_size);
- assert(!(!tag_data ^ !tag_len));
-
- tag = PPPOE_PACKET_TAIL(packet);
-
- tag->tag_len = htobe16(tag_len);
- tag->tag_type = tag_type;
- if (tag_data)
- memcpy(tag->tag_data, tag_data, tag_len);
-
- packet->length = htobe16(PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len);
-}
-
-static int pppoe_send(sd_pppoe *ppp, uint8_t code) {
- union sockaddr_union link = {
- .ll = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_PPP_DISC),
- .sll_halen = ETH_ALEN,
- },
- };
- _cleanup_free_ struct pppoe_hdr *packet = NULL;
- int r;
-
- assert(ppp);
- assert(ppp->fd != -1);
- assert(IN_SET(code, PADI_CODE, PADR_CODE, PADT_CODE));
-
- link.ll.sll_ifindex = ppp->ifindex;
- if (code == PADI_CODE)
- memset(&link.ll.sll_addr, 0xff, ETH_ALEN);
- else
- memcpy(&link.ll.sll_addr, &ppp->peer_mac, ETH_ALEN);
-
- packet = malloc0(PPPOE_MAX_PACKET_SIZE);
- if (!packet)
- return -ENOMEM;
-
- packet->ver = 0x1;
- packet->type = 0x1;
- packet->code = code;
- if (code == PADT_CODE)
- packet->sid = ppp->session_id;
-
- /* Service-Name */
- pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_SRV_NAME,
- ppp->service_name, ppp->service_name ? strlen(ppp->service_name) : 0);
-
- /* AC-Cookie */
- if (code == PADR_CODE && ppp->tags.cookie)
- pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_AC_COOKIE,
- ppp->tags.cookie, ppp->tags.cookie_len);
-
- /* Host-Uniq */
- if (code != PADT_CODE) {
- ppp->host_uniq = random_u64();
-
- pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_HOST_UNIQ,
- &ppp->host_uniq, sizeof(ppp->host_uniq));
- }
-
- r = sendto(ppp->fd, packet, sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet),
- 0, &link.sa, sizeof(link.ll));
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata);
-
-static int pppoe_arm_timeout(sd_pppoe *ppp) {
- _cleanup_event_source_unref_ sd_event_source *timeout = NULL;
- usec_t next_timeout = 0;
- int r;
-
- assert(ppp);
-
- r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout);
- if (r < 0)
- return r;
-
- next_timeout += 500 * USEC_PER_MSEC;
-
- r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout,
- 10 * USEC_PER_MSEC, pppoe_timeout, ppp);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(timeout, ppp->event_priority);
- if (r < 0)
- return r;
-
- sd_event_source_unref(ppp->timeout);
- ppp->timeout = timeout;
- timeout = NULL;
-
- return 0;
-}
-
-static int pppoe_send_initiation(sd_pppoe *ppp) {
- int r;
-
- r = pppoe_send(ppp, PADI_CODE);
- if (r < 0)
- return r;
-
- log_debug("PPPoE: sent DISCOVER (Service-Name: %s)",
- strna(ppp->service_name));
-
- pppoe_arm_timeout(ppp);
-
- return r;
-}
-
-static int pppoe_send_request(sd_pppoe *ppp) {
- int r;
-
- r = pppoe_send(ppp, PADR_CODE);
- if (r < 0)
- return r;
-
- log_debug("PPPoE: sent REQUEST");
-
- ppp->padr_resend_count --;
-
- pppoe_arm_timeout(ppp);
-
- return 0;
-}
-
-static int pppoe_send_terminate(sd_pppoe *ppp) {
- int r;
-
- r = pppoe_send(ppp, PADT_CODE);
- if (r < 0)
- return r;
-
- log_debug("PPPoE: sent TERMINATE");
-
- return 0;
-}
-
-static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_pppoe *ppp = userdata;
- int r;
-
- assert(ppp);
-
- switch (ppp->state) {
- case PPPOE_STATE_INITIALIZING:
- r = pppoe_send_initiation(ppp);
- if (r < 0)
- log_warning_errno(r, "PPPoE: sending PADI failed: %m");
-
- break;
- case PPPOE_STATE_REQUESTING:
- if (ppp->padr_resend_count <= 0) {
- log_debug("PPPoE: PADR timed out, restarting PADI");
-
- r = pppoe_send_initiation(ppp);
- if (r < 0)
- log_warning_errno(r, "PPPoE: sending PADI failed: %m");
-
- ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
- ppp->state = PPPOE_STATE_INITIALIZING;
- } else {
- r = pppoe_send_request(ppp);
- if (r < 0)
- log_warning_errno(r, "PPPoE: sending PADR failed: %m");
- }
-
- break;
- default:
- assert_not_reached("timeout in invalid state");
- }
-
- return 0;
-}
-
-static int pppoe_tag_parse_binary(struct pppoe_tag *tag, uint8_t **ret, size_t *length) {
- uint8_t *data;
-
- assert(ret);
- assert(length);
-
- data = memdup(tag->tag_data, PPPOE_TAG_LENGTH(tag));
- if (!data)
- return -ENOMEM;
-
- free(*ret);
- *ret = data;
- *length = PPPOE_TAG_LENGTH(tag);
-
- return 0;
-}
-
-static int pppoe_tag_parse_string(struct pppoe_tag *tag, char **ret) {
- char *string;
-
- assert(ret);
-
- string = strndup(tag->tag_data, PPPOE_TAG_LENGTH(tag));
- if (!string)
- return -ENOMEM;
-
- free(*ret);
- *ret = string;
-
- return 0;
-}
-
-static int pppoe_payload_parse(PPPoETags *tags, struct pppoe_hdr *header) {
- struct pppoe_tag *tag;
- int r;
-
- assert(tags);
-
- pppoe_tags_clear(tags);
-
- PPPOE_TAGS_FOREACH(tag, header) {
- switch (PPPOE_TAG_TYPE(tag)) {
- case PTT_SRV_NAME:
- r = pppoe_tag_parse_string(tag, &tags->service_name);
- if (r < 0)
- return r;
-
- break;
- case PTT_AC_NAME:
- r = pppoe_tag_parse_string(tag, &tags->ac_name);
- if (r < 0)
- return r;
-
- break;
- case PTT_HOST_UNIQ:
- r = pppoe_tag_parse_binary(tag, &tags->host_uniq, &tags->host_uniq_len);
- if (r < 0)
- return r;
-
- break;
- case PTT_AC_COOKIE:
- r = pppoe_tag_parse_binary(tag, &tags->cookie, &tags->cookie_len);
- if (r < 0)
- return r;
-
- break;
- case PTT_SRV_ERR:
- case PTT_SYS_ERR:
- case PTT_GEN_ERR:
- {
- _cleanup_free_ char *error = NULL;
-
- /* TODO: do something more sensible with the error messages */
- r = pppoe_tag_parse_string(tag, &error);
- if (r < 0)
- return r;
-
- if (strlen(error) > 0 && utf8_is_valid(error))
- log_debug("PPPoE: error - '%s'", error);
- else
- log_debug("PPPoE: error");
-
- break;
- }
- default:
- log_debug("PPPoE: ignoring unknown PPPoE tag type: 0x%.2x", PPPOE_TAG_TYPE(tag));
- }
- }
-
- return 0;
-}
-
-static int pppoe_open_pppoe_socket(sd_pppoe *ppp) {
- int s;
-
- assert(ppp);
- assert(ppp->pppoe_fd == -1);
-
- s = socket(AF_PPPOX, SOCK_STREAM, 0);
- if (s < 0)
- return -errno;
-
- ppp->pppoe_fd = s;
-
- return 0;
-}
-
-static int pppoe_connect_pppoe_socket(sd_pppoe *ppp) {
- union sockaddr_union_pppox link = {
- .pppox = {
- .sa_family = AF_PPPOX,
- .sa_protocol = PX_PROTO_OE,
- },
- };
- int r, channel;
-
- assert(ppp);
- assert(ppp->pppoe_fd != -1);
- assert(ppp->session_id);
- assert(ppp->ifname);
-
- link.pppox.sa_addr.pppoe.sid = ppp->session_id;
- memcpy(link.pppox.sa_addr.pppoe.dev, ppp->ifname, strlen(ppp->ifname));
- memcpy(link.pppox.sa_addr.pppoe.remote, &ppp->peer_mac, ETH_ALEN);
-
- r = connect(ppp->pppoe_fd, &link.sa, sizeof(link.pppox));
- if (r < 0)
- return r;
-
- r = ioctl(ppp->pppoe_fd, PPPIOCGCHAN, &channel);
- if (r < 0)
- return -errno;
-
- ppp->channel = channel;
-
- return 0;
-}
-
-static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct ether_addr *mac) {
- int r;
-
- assert(packet);
-
- if (packet->ver != 0x1 || packet->type != 0x1)
- return 0;
-
- r = pppoe_payload_parse(&ppp->tags, packet);
- if (r < 0)
- return 0;
-
- switch (ppp->state) {
- case PPPOE_STATE_INITIALIZING:
- if (packet->code != PADO_CODE)
- return 0;
-
- if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) ||
- memcmp(ppp->tags.host_uniq, &ppp->host_uniq, sizeof(ppp->host_uniq)) != 0)
- return 0;
-
- log_debug("PPPoE: got OFFER (Peer: "
- "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx; "
- "Service-Name: '%s'; AC-Name: '%s')",
- mac->ether_addr_octet[0],
- mac->ether_addr_octet[1],
- mac->ether_addr_octet[2],
- mac->ether_addr_octet[3],
- mac->ether_addr_octet[4],
- mac->ether_addr_octet[5],
- strempty(ppp->tags.service_name),
- strempty(ppp->tags.ac_name));
-
- memcpy(&ppp->peer_mac, mac, ETH_ALEN);
-
- r = pppoe_open_pppoe_socket(ppp);
- if (r < 0) {
- log_warning("PPPoE: could not open socket");
- return r;
- }
-
- r = pppoe_send_request(ppp);
- if (r < 0)
- return 0;
-
- ppp->state = PPPOE_STATE_REQUESTING;
-
- break;
- case PPPOE_STATE_REQUESTING:
- if (packet->code != PADS_CODE)
- return 0;
-
- if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) ||
- memcmp(ppp->tags.host_uniq, &ppp->host_uniq,
- sizeof(ppp->host_uniq)) != 0)
- return 0;
-
- if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
- return 0;
-
- ppp->session_id = packet->sid;
-
- log_debug("PPPoE: got CONFIRMATION (Session ID: %"PRIu16")",
- be16toh(ppp->session_id));
-
- r = pppoe_connect_pppoe_socket(ppp);
- if (r < 0) {
- log_warning("PPPoE: could not connect socket");
- return r;
- }
-
- ppp->state = PPPOE_STATE_RUNNING;
-
- ppp->timeout = sd_event_source_unref(ppp->timeout);
- assert(ppp->cb);
- ppp->cb(ppp, SD_PPPOE_EVENT_RUNNING, ppp->userdata);
-
- break;
- case PPPOE_STATE_RUNNING:
- if (packet->code != PADT_CODE)
- return 0;
-
- if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
- return 0;
-
- if (ppp->session_id != packet->sid)
- return 0;
-
- log_debug("PPPoE: got TERMINATE");
-
- ppp->state = PPPOE_STATE_STOPPED;
-
- assert(ppp->cb);
- ppp->cb(ppp, SD_PPPOE_EVENT_STOPPED, ppp->userdata);
-
- break;
- case PPPOE_STATE_STOPPED:
- break;
- default:
- assert_not_reached("PPPoE: invalid state when receiving message");
- }
-
- return 0;
-}
-
-static int pppoe_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- sd_pppoe *ppp = userdata;
- _cleanup_free_ struct pppoe_hdr *packet = NULL;
- union sockaddr_union link = {};
- socklen_t addrlen = sizeof(link);
- int buflen = 0, len, r;
-
- assert(ppp);
- assert(fd != -1);
-
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return r;
-
- if (buflen < 0)
- /* this can't be right */
- return -EIO;
-
- packet = malloc0(buflen);
- if (!packet)
- return -ENOMEM;
-
- len = recvfrom(fd, packet, buflen, 0, &link.sa, &addrlen);
- if (len < 0) {
- log_warning_errno(r, "PPPoE: could not receive message from raw socket: %m");
- return 0;
- } else if ((size_t)len < sizeof(struct pppoe_hdr))
- return 0;
- else if ((size_t)len != sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
- return 0;
-
- if (link.ll.sll_halen != ETH_ALEN)
- /* not ethernet? */
- return 0;
-
- r = pppoe_handle_message(ppp, packet, (struct ether_addr*)&link.ll.sll_addr);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-int sd_pppoe_start(sd_pppoe *ppp) {
- union sockaddr_union link = {
- .ll = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_PPP_DISC),
- },
- };
- _cleanup_close_ int s = -1;
- _cleanup_event_source_unref_ sd_event_source *io = NULL;
- int r;
-
- assert_return(ppp, -EINVAL);
- assert_return(ppp->fd == -1, -EBUSY);
- assert_return(!ppp->io, -EBUSY);
- assert_return(ppp->ifindex > 0, -EUNATCH);
- assert_return(ppp->ifname, -EUNATCH);
- assert_return(ppp->event, -EUNATCH);
- assert_return(ppp->cb, -EUNATCH);
-
- s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- link.ll.sll_ifindex = ppp->ifindex;
-
- r = bind(s, &link.sa, sizeof(link.ll));
- if (r < 0)
- return r;
-
- r = sd_event_add_io(ppp->event, &io,
- s, EPOLLIN, pppoe_receive_message,
- ppp);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(io, ppp->event_priority);
- if (r < 0)
- return r;
-
- ppp->fd = s;
- s = -1;
- ppp->io = io;
- io = NULL;
-
- r = pppoe_send_initiation(ppp);
- if (r < 0)
- return r;
-
- ppp->state = PPPOE_STATE_INITIALIZING;
-
- return 0;
-}
-
-int sd_pppoe_stop(sd_pppoe *ppp) {
- assert_return(ppp, -EINVAL);
-
- if (ppp->state == PPPOE_STATE_RUNNING)
- pppoe_send_terminate(ppp);
-
- ppp->io = sd_event_source_unref(ppp->io);
- ppp->timeout = sd_event_source_unref(ppp->timeout);
- ppp->fd = asynchronous_close(ppp->fd);
- ppp->pppoe_fd = asynchronous_close(ppp->pppoe_fd);
-
- return 0;
-}
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
deleted file mode 100644
index 6ea460d9ac..0000000000
--- a/src/libsystemd-network/test-pppoe.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
-
- 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 <linux/veth.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sched.h>
-
-#include "sd-event.h"
-#include "sd-netlink.h"
-#include "sd-pppoe.h"
-
-#include "event-util.h"
-#include "process-util.h"
-#include "util.h"
-
-static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) {
- static int pppoe_state = -1;
- sd_event *e = userdata;
-
- assert_se(ppp);
- assert_se(e);
-
- switch (event) {
- case SD_PPPOE_EVENT_RUNNING:
- assert_se(pppoe_state == -1);
- log_info("running");
- break;
- case SD_PPPOE_EVENT_STOPPED:
- assert_se(pppoe_state == SD_PPPOE_EVENT_RUNNING);
- log_info("stopped");
- assert_se(sd_event_exit(e, 0) >= 0);
- break;
- default:
- assert_not_reached("invalid pppoe event");
- }
-
- pppoe_state = event;
-}
-
-static int client_run(const char *client_name, sd_event *e) {
- sd_pppoe *pppoe;
- int client_ifindex;
-
- client_ifindex = (int) if_nametoindex(client_name);
- assert_se(client_ifindex > 0);
-
- assert_se(sd_pppoe_new(&pppoe) >= 0);
- assert_se(sd_pppoe_attach_event(pppoe, e, 0) >= 0);
-
- assert_se(sd_pppoe_set_ifname(pppoe, "pppoe-client") >= 0);
- assert_se(sd_pppoe_set_ifindex(pppoe, client_ifindex) >= 0);
- assert_se(sd_pppoe_set_callback(pppoe, pppoe_handler, e) >= 0);
-
- log_info("starting PPPoE client, it will exit when the server times out and sends PADT");
-
- assert_se(sd_pppoe_start(pppoe) >= 0);
-
- assert_se(sd_event_loop(e) >= 0);
-
- assert_se(!sd_pppoe_unref(pppoe));
-
- return EXIT_SUCCESS;
-}
-
-static int test_pppoe_server(sd_event *e) {
- sd_netlink *rtnl;
- sd_netlink_message *m;
- pid_t pid;
- int r, client_ifindex, server_ifindex;
-
- r = unshare(CLONE_NEWNET);
- if (r < 0 && errno == EPERM)
- return EXIT_TEST_SKIP;
-
- assert_se(r >= 0);
-
- assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
- assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0);
- assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
- assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0);
- assert_se(sd_netlink_message_open_container(m, VETH_INFO_PEER) >= 0);
- assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0);
- assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
- client_ifindex = (int) if_nametoindex("pppoe-client");
- assert_se(client_ifindex > 0);
- server_ifindex = (int) if_nametoindex("pppoe-server");
- assert_se(server_ifindex > 0);
-
- m = sd_netlink_message_unref(m);
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, client_ifindex) >= 0);
- assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
- assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
- m = sd_netlink_message_unref(m);
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, server_ifindex) >= 0);
- assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
- assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
- pid = fork();
- assert_se(pid >= 0);
- if (pid == 0) {
- /* let the client send some discover messages before the server is started */
- sleep(2);
-
- /* TODO: manage pppoe-server-options */
- execlp("pppoe-server", "pppoe-server", "-F",
- "-I", "pppoe-server",
- "-C", "Test-AC",
- "-S", "Service-Default",
- "-S", "Service-First-Auxiliary",
- "-S", "Service-Second-Auxiliary",
- NULL);
- assert_not_reached("failed to execute pppoe-server. not installed?");
- }
-
- client_run("pppoe-client", e);
-
- assert_se(kill(pid, SIGTERM) >= 0);
- assert_se(wait_for_terminate(pid, NULL) >= 0);
-
- assert_se(!sd_netlink_message_unref(m));
- assert_se(!sd_netlink_unref(rtnl));
-
- return EXIT_SUCCESS;
-}
-
-int main(int argc, char *argv[]) {
- _cleanup_event_unref_ sd_event *e = NULL;
-
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
-
- assert_se(sd_event_new(&e) >= 0);
-
- if (argc == 1) {
- log_info("running PPPoE client against local server");
-
- return test_pppoe_server(e);
- } else if (argc == 2) {
- log_info("running PPPoE client over '%s'", argv[1]);
-
- return client_run(argv[1], e);
- } else {
- log_error("This program takes one or no arguments.\n"
- "\t %s [<ifname>]", program_invocation_short_name);
- return EXIT_FAILURE;
- }
-}
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 27045e25d0..f1e9b7ed1b 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -58,8 +58,7 @@ static void unsetenv_all(bool unset_environment) {
_public_ int sd_listen_fds(int unset_environment) {
const char *e;
- unsigned n;
- int r, fd;
+ int n, r, fd;
pid_t pid;
e = getenv("LISTEN_PID");
@@ -84,17 +83,23 @@ _public_ int sd_listen_fds(int unset_environment) {
goto finish;
}
- r = safe_atou(e, &n);
+ r = safe_atoi(e, &n);
if (r < 0)
goto finish;
- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
+ assert_cc(SD_LISTEN_FDS_START < INT_MAX);
+ if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
+ r = -EINVAL;
+ goto finish;
+ }
+
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
r = fd_cloexec(fd, true);
if (r < 0)
goto finish;
}
- r = (int) n;
+ r = n;
finish:
unsetenv_all(unset_environment);
@@ -586,7 +591,7 @@ _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
r = safe_atou64(s, &u);
if (r < 0)
goto finish;
- if (u <= 0) {
+ if (u <= 0 || u >= USEC_INFINITY) {
r = -EINVAL;
goto finish;
}
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 0d40bc5c00..0e49262087 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -356,13 +356,10 @@ int device_set_ifindex(sd_device *device, const char *_ifindex) {
assert(device);
assert(_ifindex);
- r = safe_atoi(_ifindex, &ifindex);
+ r = parse_ifindex(_ifindex, &ifindex);
if (r < 0)
return r;
- if (ifindex <= 0)
- return -EINVAL;
-
r = device_add_property_internal(device, "IFINDEX", _ifindex);
if (r < 0)
return r;
@@ -632,11 +629,9 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
struct ifreq ifr = {};
int ifindex;
- r = safe_atoi(&id[1], &ifr.ifr_ifindex);
+ r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
if (r < 0)
return r;
- else if (ifr.ifr_ifindex <= 0)
- return -EINVAL;
sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index cd766c3f91..3f2e459825 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -932,9 +932,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
*(char*) (mempcpy(buf, word, l)) = 0;
- if (safe_atoi(buf, &ifi) < 0)
- continue;
- if (ifi <= 0)
+ if (parse_ifindex(buf, &ifi) < 0)
continue;
if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
diff --git a/src/login/logind.c b/src/login/logind.c
index 4b8c834269..d1e2ea2489 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -31,6 +31,7 @@
#include "bus-error.h"
#include "bus-util.h"
#include "conf-parser.h"
+#include "def.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "formats-util.h"
diff --git a/src/machine/machine.c b/src/machine/machine.c
index df8391c996..cbc03640c1 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -323,15 +323,16 @@ int machine_load(Machine *m) {
int ifi;
r = extract_first_word(&p, &word, NULL, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to parse NETIF: %s", netif);
-
if (r == 0)
break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse NETIF: %s", netif);
+ break;
+ }
- if (safe_atoi(word, &ifi) < 0)
- continue;
- if (ifi <= 0)
+ if (parse_ifindex(word, &ifi) < 0)
continue;
if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 830ca7b89d..b90c50719f 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include "conf-files.h"
+#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 97c1fe6560..ba7e3ba74a 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -521,7 +521,7 @@ static int link_status_one(
assert(rtnl);
assert(name);
- if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
+ if (parse_ifindex(name, &ifindex) >= 0)
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
else {
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index e550ee5701..8b6acf2e1d 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -271,15 +271,35 @@ int address_add_foreign(Link *link, int family, const union in_addr_union *in_ad
return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
}
-static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ Address *address;
int r;
- r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, ret);
- if (r < 0)
+ r = address_get(link, family, in_addr, prefixlen, &address);
+ if (r == -ENOENT) {
+ /* Address does not exist, create a new one */
+ r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
+ if (r < 0)
+ return r;
+ } else if (r == 0) {
+ /* Take over a foreign address */
+ r = set_ensure_allocated(&link->addresses, &address_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(link->addresses, address);
+ if (r < 0)
+ return r;
+
+ set_remove(link->addresses_foreign, address);
+ } else if (r == 1) {
+ /* Already exists, do nothing */
+ ;
+ } else
return r;
- link_update_operstate(link);
- link_dirty(link);
+ if (ret)
+ *ret = address;
return 0;
}
@@ -318,8 +338,12 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
address->scope = scope;
address->cinfo = *cinfo;
- if (!ready && address_is_ready(address) && address->link)
- link_check_ready(address->link);
+ if (address->link) {
+ link_update_operstate(address->link);
+
+ if (!ready && address_is_ready(address))
+ link_check_ready(address->link);
+ }
return 0;
}
@@ -356,7 +380,11 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi
address.prefixlen = prefixlen;
existing = set_get(link->addresses, &address);
- if (!existing) {
+ if (existing) {
+ *ret = existing;
+
+ return 1;
+ } else {
existing = set_get(link->addresses_foreign, &address);
if (!existing)
return -ENOENT;
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index fd309bebb6..0b1f3b688b 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -62,6 +62,7 @@ int address_new_static(Network *network, unsigned section, Address **ret);
int address_new(Address **ret);
void address_free(Address *address);
int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
int address_drop(Address *address);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index c412a2cc31..b58fc5808c 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -87,12 +87,12 @@ static int link_set_dhcp_routes(Link *link) {
* route for the gw host so that we can route no matter the
* netmask or existing kernel route tables. */
route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
+ route_gw->dst.in = gateway;
route_gw->dst_prefixlen = 32;
- route_gw->prefsrc_addr.in = address;
+ route_gw->prefsrc.in = address;
route_gw->scope = RT_SCOPE_LINK;
route_gw->protocol = RTPROT_DHCP;
- route_gw->metrics = link->network->dhcp_route_metric;
+ route_gw->priority = link->network->dhcp_route_metric;
r = route_configure(route_gw, link, &dhcp4_route_handler);
if (r < 0)
@@ -101,9 +101,9 @@ static int link_set_dhcp_routes(Link *link) {
link->dhcp4_messages ++;
route->family = AF_INET;
- route->in_addr.in = gateway;
- route->prefsrc_addr.in = address;
- route->metrics = link->network->dhcp_route_metric;
+ route->gw.in = gateway;
+ route->prefsrc.in = address;
+ route->priority = link->network->dhcp_route_metric;
r = route_configure(route, link, &dhcp4_route_handler);
if (r < 0) {
@@ -130,10 +130,10 @@ static int link_set_dhcp_routes(Link *link) {
route->family = AF_INET;
route->protocol = RTPROT_DHCP;
- route->in_addr.in = static_routes[i].gw_addr;
- route->dst_addr.in = static_routes[i].dst_addr;
+ route->gw.in = static_routes[i].gw_addr;
+ route->dst.in = static_routes[i].dst_addr;
route->dst_prefixlen = static_routes[i].dst_prefixlen;
- route->metrics = link->network->dhcp_route_metric;
+ route->priority = link->network->dhcp_route_metric;
r = route_configure(route, link, &dhcp4_route_handler);
if (r < 0)
@@ -170,8 +170,8 @@ static int dhcp_lease_lost(Link *link) {
r = route_new(&route);
if (r >= 0) {
route->family = AF_INET;
- route->in_addr.in = routes[i].gw_addr;
- route->dst_addr.in = routes[i].dst_addr;
+ route->gw.in = routes[i].gw_addr;
+ route->dst.in = routes[i].dst_addr;
route->dst_prefixlen = routes[i].dst_prefixlen;
route_remove(route, link,
@@ -191,7 +191,7 @@ static int dhcp_lease_lost(Link *link) {
r = route_new(&route_gw);
if (r >= 0) {
route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
+ route_gw->dst.in = gateway;
route_gw->dst_prefixlen = 32;
route_gw->scope = RT_SCOPE_LINK;
@@ -202,7 +202,7 @@ static int dhcp_lease_lost(Link *link) {
r = route_new(&route);
if (r >= 0) {
route->family = AF_INET;
- route->in_addr.in = gateway;
+ route->gw.in = gateway;
route_remove(route, link,
&link_route_remove_handler);
@@ -533,9 +533,11 @@ int dhcp4_configure(Link *link) {
assert(link->network);
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
- r = sd_dhcp_client_new(&link->dhcp_client);
- if (r < 0)
- return r;
+ if (!link->dhcp_client) {
+ r = sd_dhcp_client_new(&link->dhcp_client);
+ if (r < 0)
+ return r;
+ }
r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
if (r < 0)
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 2fdb77ef6c..ed0d861e7a 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -63,7 +63,7 @@ static int ipv4ll_address_lost(Link *link) {
route->family = AF_INET;
route->scope = RT_SCOPE_LINK;
- route->metrics = IPV4LL_ROUTE_METRIC;
+ route->priority = IPV4LL_ROUTE_METRIC;
route_remove(route, link, &link_route_remove_handler);
@@ -156,7 +156,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
route->family = AF_INET;
route->scope = RT_SCOPE_LINK;
route->protocol = RTPROT_STATIC;
- route->metrics = IPV4LL_ROUTE_METRIC;
+ route->priority = IPV4LL_ROUTE_METRIC;
r = route_configure(route, link, ipv4ll_route_handler);
if (r < 0)
@@ -208,9 +208,11 @@ int ipv4ll_configure(Link *link) {
assert(link->network);
assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
- r = sd_ipv4ll_new(&link->ipv4ll);
- if (r < 0)
- return r;
+ if (!link->ipv4ll) {
+ r = sd_ipv4ll_new(&link->ipv4ll);
+ if (r < 0)
+ return r;
+ }
if (link->udev_device) {
r = net_get_unique_predictable_data(link->udev_device, seed);
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index 7fc4510ac9..11b35d6cf8 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -103,7 +103,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
if (r < 0)
return 0;
- r = safe_atoi(identifier, &ifindex);
+ r = parse_ifindex(identifier, &ifindex);
if (r < 0)
return 0;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 12ca02868d..46979ffa12 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -26,6 +26,7 @@
#include "alloc-util.h"
#include "bus-util.h"
#include "dhcp-lease-internal.h"
+#include "event-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "netlink-util.h"
@@ -2057,28 +2058,30 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
if (r < 0)
return r;
- r = network_get(link->manager, link->udev_device, link->ifname,
- &link->mac, &network);
- if (r == -ENOENT) {
- link_enter_unmanaged(link);
- return 1;
- } else if (r < 0)
- return r;
+ if (!link->network) {
+ r = network_get(link->manager, link->udev_device, link->ifname,
+ &link->mac, &network);
+ if (r == -ENOENT) {
+ link_enter_unmanaged(link);
+ return 1;
+ } else if (r < 0)
+ return r;
- if (link->flags & IFF_LOOPBACK) {
- if (network->link_local != ADDRESS_FAMILY_NO)
- log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
+ if (link->flags & IFF_LOOPBACK) {
+ if (network->link_local != ADDRESS_FAMILY_NO)
+ log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
- if (network->dhcp != ADDRESS_FAMILY_NO)
- log_link_debug(link, "Ignoring DHCP clients for loopback link");
+ if (network->dhcp != ADDRESS_FAMILY_NO)
+ log_link_debug(link, "Ignoring DHCP clients for loopback link");
- if (network->dhcp_server)
- log_link_debug(link, "Ignoring DHCP server for loopback link");
- }
+ if (network->dhcp_server)
+ log_link_debug(link, "Ignoring DHCP server for loopback link");
+ }
- r = network_apply(link->manager, network, link);
- if (r < 0)
- return r;
+ r = network_apply(link->manager, network, link);
+ if (r < 0)
+ return r;
+ }
r = link_new_bound_to_list(link);
if (r < 0)
@@ -2130,6 +2133,193 @@ int link_initialized(Link *link, struct udev_device *device) {
return 0;
}
+static int link_load(Link *link) {
+ _cleanup_free_ char *network_file = NULL,
+ *addresses = NULL,
+ *routes = NULL,
+ *dhcp4_address = NULL,
+ *ipv4ll_address = NULL;
+ union in_addr_union address;
+ union in_addr_union route_dst;
+ const char *p;
+ int r;
+
+ assert(link);
+
+ r = parse_env_file(link->state_file, NEWLINE,
+ "NETWORK_FILE", &network_file,
+ "ADDRESSES", &addresses,
+ "ROUTES", &routes,
+ "DHCP4_ADDRESS", &dhcp4_address,
+ "IPV4LL_ADDRESS", &ipv4ll_address,
+ NULL);
+ if (r < 0 && r != -ENOENT)
+ return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
+
+ if (network_file) {
+ Network *network;
+ char *suffix;
+
+ /* drop suffix */
+ suffix = strrchr(network_file, '.');
+ if (!suffix) {
+ log_link_debug(link, "Failed to get network name from %s", network_file);
+ goto network_file_fail;
+ }
+ *suffix = '\0';
+
+ r = network_get_by_name(link->manager, basename(network_file), &network);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file));
+ goto network_file_fail;
+ }
+
+ r = network_apply(link->manager, network, link);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
+ }
+
+network_file_fail:
+
+ if (addresses) {
+ p = addresses;
+
+ for (;;) {
+ _cleanup_free_ char *address_str = NULL;
+ char *prefixlen_str;
+ int family;
+ unsigned char prefixlen;
+
+ r = extract_first_word(&p, &address_str, NULL, 0);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to extract next address string: %m");
+ continue;
+ } if (r == 0)
+ break;
+
+ prefixlen_str = strchr(address_str, '/');
+ if (!prefixlen_str) {
+ log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
+ continue;
+ }
+
+ *prefixlen_str ++ = '\0';
+
+ r = sscanf(prefixlen_str, "%hhu", &prefixlen);
+ if (r != 1) {
+ log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
+ continue;
+ }
+
+ r = in_addr_from_string_auto(address_str, &family, &address);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
+ continue;
+ }
+
+ r = address_add(link, family, &address, prefixlen, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to add address: %m");
+ }
+ }
+
+ if (routes) {
+ for (;;) {
+ Route *route;
+ _cleanup_free_ char *route_str = NULL;
+ _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+ usec_t lifetime;
+ char *prefixlen_str;
+ int family;
+ unsigned char prefixlen, tos, table;
+ uint32_t priority;
+
+ r = extract_first_word(&p, &route_str, NULL, 0);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to extract next route string: %m");
+ continue;
+ } if (r == 0)
+ break;
+
+ prefixlen_str = strchr(route_str, '/');
+ if (!prefixlen_str) {
+ log_link_debug(link, "Failed to parse route %s", route_str);
+ continue;
+ }
+
+ *prefixlen_str ++ = '\0';
+
+ r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
+ if (r != 5) {
+ log_link_debug(link,
+ "Failed to parse destination prefix length, tos, priority, table or expiration %s",
+ prefixlen_str);
+ continue;
+ }
+
+ r = in_addr_from_string_auto(route_str, &family, &route_dst);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
+ continue;
+ }
+
+ r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to add route: %m");
+
+ if (lifetime != USEC_INFINITY) {
+ r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
+ 0, route_expire_handler, route);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
+ }
+
+ route->lifetime = lifetime;
+ sd_event_source_unref(route->expire);
+ route->expire = expire;
+ expire = NULL;
+ }
+ }
+
+ if (dhcp4_address) {
+ r = in_addr_from_string(AF_INET, dhcp4_address, &address);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address);
+ goto dhcp4_address_fail;
+ }
+
+ r = sd_dhcp_client_new(&link->dhcp_client);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m");
+
+ r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address);
+ }
+
+dhcp4_address_fail:
+
+ if (ipv4ll_address) {
+ r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address);
+ goto ipv4ll_address_fail;
+ }
+
+ r = sd_ipv4ll_new(&link->ipv4ll);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m");
+
+ r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address);
+ }
+
+ipv4ll_address_fail:
+
+ return 0;
+}
+
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
Link *link;
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
@@ -2149,6 +2339,10 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
log_link_debug(link, "Link %d added", link->ifindex);
+ r = link_load(link);
+ if (r < 0)
+ return r;
+
if (detect_container() <= 0) {
/* not in a container, udev will be around */
sprintf(ifindex_str, "n%d", link->ifindex);
@@ -2372,6 +2566,7 @@ int link_save(Link *link) {
_cleanup_fclose_ FILE *f = NULL;
const char *admin_state, *oper_state;
Address *a;
+ Route *route;
Iterator i;
int r;
@@ -2450,9 +2645,9 @@ int link_save(Link *link) {
}
}
- fputs("\n", f);
+ fputc('\n', f);
- fprintf(f, "NTP=");
+ fputs("NTP=", f);
space = false;
STRV_FOREACH(address, link->network->ntp) {
if (space)
@@ -2499,9 +2694,9 @@ int link_save(Link *link) {
}
}
- fputs("\n", f);
+ fputc('\n', f);
- fprintf(f, "DOMAINS=");
+ fputs("DOMAINS=", f);
space = false;
STRV_FOREACH(domain, link->network->domains) {
if (space)
@@ -2537,7 +2732,7 @@ int link_save(Link *link) {
}
}
- fputs("\n", f);
+ fputc('\n', f);
fprintf(f, "WILDCARD_DOMAIN=%s\n",
yes_no(link->network->wildcard_domain));
@@ -2545,7 +2740,7 @@ int link_save(Link *link) {
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->network->llmnr));
- fprintf(f, "ADDRESSES=");
+ fputs("ADDRESSES=", f);
space = false;
SET_FOREACH(a, link->addresses, i) {
_cleanup_free_ char *address_str = NULL;
@@ -2558,7 +2753,23 @@ int link_save(Link *link) {
space = true;
}
- fputs("\n", f);
+ fputc('\n', f);
+
+ fputs("ROUTES=", f);
+ space = false;
+ SET_FOREACH(route, link->routes, i) {
+ _cleanup_free_ char *route_str = NULL;
+
+ r = in_addr_to_string(route->family, &route->dst, &route_str);
+ if (r < 0)
+ goto fail;
+
+ fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
+ route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
+ space = true;
+ }
+
+ fputc('\n', f);
}
if (!hashmap_isempty(link->bound_to_links)) {
@@ -2573,7 +2784,7 @@ int link_save(Link *link) {
space = true;
}
- fputs("\n", f);
+ fputc('\n', f);
}
if (!hashmap_isempty(link->bound_by_links)) {
@@ -2588,19 +2799,25 @@ int link_save(Link *link) {
space = true;
}
- fputs("\n", f);
+ fputc('\n', f);
}
if (link->dhcp_lease) {
+ struct in_addr address;
const char *tz = NULL;
+ assert(link->network);
+
r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
if (r >= 0)
fprintf(f, "TIMEZONE=%s\n", tz);
- }
- if (link->dhcp_lease) {
- assert(link->network);
+ r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
+ if (r >= 0) {
+ fputs("DHCP4_ADDRESS=", f);
+ serialize_in_addrs(f, &address, 1);
+ fputc('\n', f);
+ }
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
@@ -2612,6 +2829,17 @@ int link_save(Link *link) {
} else
unlink(link->lease_file);
+ if (link->ipv4ll) {
+ struct in_addr address;
+
+ r = sd_ipv4ll_get_address(link->ipv4ll, &address);
+ if (r >= 0) {
+ fputs("IPV4LL_ADDRESS=", f);
+ serialize_in_addrs(f, &address, 1);
+ fputc('\n', f);
+ }
+ }
+
if (link->lldp) {
assert(link->network);
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 2a69f1c16b..a22041870e 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -85,6 +85,8 @@ struct Link {
Set *addresses;
Set *addresses_foreign;
+ Set *routes;
+ Set *routes_foreign;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 6b2a661ca7..a5701001c1 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -279,6 +279,196 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
+int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ Manager *m = userdata;
+ Link *link = NULL;
+ uint16_t type;
+ uint32_t ifindex, priority = 0;
+ unsigned char protocol, scope, tos, table;
+ int family;
+ unsigned char dst_prefixlen, src_prefixlen;
+ union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
+ Route *route = NULL;
+ int r;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive route: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+ log_warning("rtnl: received unexpected message type when processing route");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
+ if (r == -ENODATA) {
+ log_debug("rtnl: received route without ifindex, ignoring");
+ return 0;
+ } else if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m");
+ return 0;
+ } else if (ifindex <= 0) {
+ log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex);
+ return 0;
+ } else {
+ r = link_get(m, ifindex, &link);
+ if (r < 0 || !link) {
+ /* when enumerating we might be out of sync, but we will
+ * get the route again, so just ignore it */
+ if (!m->enumerating)
+ log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex);
+ return 0;
+ }
+ }
+
+ r = sd_rtnl_message_route_get_family(message, &family);
+ if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+ log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_protocol(message, &protocol);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get route protocol: %m");
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ default:
+ log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_scope(message, &scope);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_tos(message, &tos);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_table(message, &table);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m");
+ return 0;
+ }
+
+ route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+
+ switch (type) {
+ case RTM_NEWROUTE:
+ if (!route) {
+ /* A route appeared that we did not request */
+ r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+ if (r < 0)
+ return 0;
+ }
+
+ route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol);
+
+ break;
+
+ case RTM_DELROUTE:
+
+ if (route)
+ route_drop(route);
+
+ break;
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
@@ -377,7 +567,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
break;
default:
- assert_not_reached("invalid address family");
+ log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
}
if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
@@ -572,6 +762,14 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
+ r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -1019,6 +1217,41 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
return r;
}
+int manager_rtnl_enumerate_routes(Manager *m) {
+ _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+ sd_netlink_message *route;
+ int r;
+
+ assert(m);
+ assert(m->rtnl);
+
+ r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(m->rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (route = reply; route; route = sd_netlink_message_next(route)) {
+ int k;
+
+ m->enumerating = true;
+
+ k = manager_rtnl_process_route(m->rtnl, route, m);
+ if (k < 0)
+ r = k;
+
+ m->enumerating = false;
+ }
+
+ return r;
+}
+
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
AddressPool *p;
int r;
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 2eeb86a683..57c58d83b4 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -72,20 +72,21 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+ /* convert to jiffes */
if (b->forward_delay > 0) {
- r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, b->forward_delay / USEC_PER_SEC);
+ r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay));
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m");
}
if (b->hello_time > 0) {
- r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, b->hello_time / USEC_PER_SEC );
+ r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time));
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m");
}
if (b->max_age > 0) {
- r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, b->max_age / USEC_PER_SEC);
+ r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age));
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
}
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index cc8d019017..0188cb6fe5 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -352,6 +352,10 @@ int network_get(Manager *manager, struct udev_device *device,
int network_apply(Manager *manager, Network *network, Link *link) {
int r;
+ assert(manager);
+ assert(network);
+ assert(link);
+
link->network = network;
if (network->ipv4ll_route) {
@@ -361,7 +365,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
if (r < 0)
return r;
- r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
+ r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
if (r == 0)
return -EINVAL;
if (r < 0)
@@ -370,7 +374,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
route->family = AF_INET;
route->dst_prefixlen = 16;
route->scope = RT_SCOPE_LINK;
- route->metrics = IPV4LL_ROUTE_METRIC;
+ route->priority = IPV4LL_ROUTE_METRIC;
route->protocol = RTPROT_STATIC;
}
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 4a74bc69f3..f4bbd06af1 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -21,11 +21,13 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "event-util.h"
#include "in-addr-util.h"
#include "netlink-util.h"
#include "networkd-route.h"
#include "networkd.h"
#include "parse-util.h"
+#include "set.h"
#include "string-util.h"
#include "util.h"
@@ -40,6 +42,7 @@ int route_new(Route **ret) {
route->scope = RT_SCOPE_UNIVERSE;
route->protocol = RTPROT_UNSPEC;
route->table = RT_TABLE_DEFAULT;
+ route->lifetime = USEC_INFINITY;
*ret = route;
route = NULL;
@@ -95,6 +98,13 @@ void route_free(Route *route) {
UINT_TO_PTR(route->section));
}
+ if (route->link) {
+ set_remove(route->link->routes, route);
+ set_remove(route->link->routes_foreign, route);
+ }
+
+ sd_event_source_unref(route->expire);
+
free(route);
}
@@ -110,7 +120,7 @@ static void route_hash_func(const void *b, struct siphash *state) {
case AF_INET6:
/* Equality of routes are given by the 4-touple
(dst_prefix,dst_prefixlen,tos,priority,table) */
- siphash24_compress(&route->dst_addr, FAMILY_ADDRESS_SIZE(route->family), state);
+ siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
siphash24_compress(&route->tos, sizeof(route->tos), state);
siphash24_compress(&route->priority, sizeof(route->priority), state);
@@ -134,7 +144,6 @@ static int route_compare_func(const void *_a, const void *_b) {
switch (a->family) {
case AF_INET:
case AF_INET6:
- //TODO: check IPv6 routes
if (a->dst_prefixlen < b->dst_prefixlen)
return -1;
if (a->dst_prefixlen > b->dst_prefixlen)
@@ -155,7 +164,7 @@ static int route_compare_func(const void *_a, const void *_b) {
if (a->table > b->table)
return 1;
- return memcmp(&a->dst_addr, &b->dst_addr, FAMILY_ADDRESS_SIZE(a->family));
+ return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
default:
/* treat any other address family as AF_UNSPEC */
return 0;
@@ -167,6 +176,162 @@ static const struct hash_ops route_hash_ops = {
.compare = route_compare_func
};
+int route_get(Link *link,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table,
+ Route **ret) {
+ Route route = {
+ .family = family,
+ .dst_prefixlen = dst_prefixlen,
+ .tos = tos,
+ .priority = priority,
+ .table = table,
+ }, *existing;
+
+ assert(link);
+ assert(dst);
+ assert(ret);
+
+ route.dst = *dst;
+
+ existing = set_get(link->routes, &route);
+ if (existing) {
+ *ret = existing;
+ return 1;
+ } else {
+ existing = set_get(link->routes_foreign, &route);
+ if (!existing)
+ return -ENOENT;
+ }
+
+ *ret = existing;
+
+ return 0;
+}
+
+static int route_add_internal(Link *link, Set **routes,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table, Route **ret) {
+ _cleanup_route_free_ Route *route = NULL;
+ int r;
+
+ assert(link);
+ assert(routes);
+ assert(dst);
+
+ r = route_new(&route);
+ if (r < 0)
+ return r;
+
+ route->family = family;
+ route->dst = *dst;
+ route->dst_prefixlen = dst_prefixlen;
+ route->tos = tos;
+ route->priority = priority;
+ route->table = table;
+
+ r = set_ensure_allocated(routes, &route_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(*routes, route);
+ if (r < 0)
+ return r;
+
+ route->link = link;
+
+ if (ret)
+ *ret = route;
+
+ route = NULL;
+
+ return 0;
+}
+
+int route_add_foreign(Link *link,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table, Route **ret) {
+ return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
+}
+
+int route_add(Link *link,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table, Route **ret) {
+ Route *route;
+ int r;
+
+ r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
+ if (r == -ENOENT) {
+ /* Route does not exist, create a new one */
+ r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
+ if (r < 0)
+ return r;
+ } else if (r == 0) {
+ /* Take over a foreign route */
+ r = set_ensure_allocated(&link->routes, &route_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(link->routes, route);
+ if (r < 0)
+ return r;
+
+ set_remove(link->routes_foreign, route);
+ } else if (r == 1) {
+ /* Route exists, do nothing */
+ ;
+ } else
+ return r;
+
+ *ret = route;
+
+ return 0;
+}
+
+int route_update(Route *route,
+ union in_addr_union *src,
+ unsigned char src_prefixlen,
+ union in_addr_union *gw,
+ union in_addr_union *prefsrc,
+ unsigned char scope,
+ unsigned char protocol) {
+ assert(route);
+ assert(src);
+ assert(gw);
+ assert(prefsrc);
+
+ route->src = *src;
+ route->src_prefixlen = src_prefixlen;
+ route->gw = *gw;
+ route->prefsrc = *prefsrc;
+ route->scope = scope;
+ route->protocol = protocol;
+
+ return 0;
+}
+
+void route_drop(Route *route) {
+ assert(route);
+
+ route_free(route);
+}
+
int route_remove(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
@@ -184,20 +349,20 @@ int route_remove(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
- if (!in_addr_is_null(route->family, &route->in_addr)) {
+ if (!in_addr_is_null(route->family, &route->gw)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
}
if (route->dst_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
@@ -208,9 +373,9 @@ int route_remove(Route *route, Link *link,
if (route->src_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
@@ -219,11 +384,11 @@ int route_remove(Route *route, Link *link,
return log_error_errno(r, "Could not set source prefix length: %m");
}
- if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
+ if (!in_addr_is_null(route->family, &route->prefsrc)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
}
@@ -232,7 +397,7 @@ int route_remove(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
- r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
+ r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
@@ -249,9 +414,24 @@ int route_remove(Route *route, Link *link,
return 0;
}
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+ Route *route = userdata;
+ int r;
+
+ assert(route);
+
+ r = route_remove(route, route->link, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Could not remove route: %m");
+
+ return 1;
+}
+
int route_configure(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+ _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+ usec_t lifetime;
int r;
assert(link);
@@ -266,20 +446,20 @@ int route_configure(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
- if (!in_addr_is_null(route->family, &route->in_addr)) {
+ if (!in_addr_is_null(route->family, &route->gw)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
}
if (route->dst_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
@@ -290,9 +470,9 @@ int route_configure(Route *route, Link *link,
if (route->src_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
@@ -301,11 +481,11 @@ int route_configure(Route *route, Link *link,
return log_error_errno(r, "Could not set source prefix length: %m");
}
- if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
+ if (!in_addr_is_null(route->family, &route->prefsrc)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
}
@@ -314,7 +494,7 @@ int route_configure(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
- r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
+ r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
@@ -328,6 +508,26 @@ int route_configure(Route *route, Link *link,
link_ref(link);
+ lifetime = route->lifetime;
+
+ r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
+ if (r < 0)
+ return log_error_errno(r, "Could not add route: %m");
+
+ /* TODO: drop expiration handling once it can be pushed into the kernel */
+ route->lifetime = lifetime;
+
+ if (route->lifetime != USEC_INFINITY) {
+ r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
+ route->lifetime, 0, route_expire_handler, route);
+ if (r < 0)
+ return log_error_errno(r, "Could not arm expiration timer: %m");
+ }
+
+ sd_event_source_unref(route->expire);
+ route->expire = expire;
+ expire = NULL;
+
return 0;
}
@@ -370,7 +570,7 @@ int config_parse_gateway(const char *unit,
}
n->family = f;
- n->in_addr = buffer;
+ n->gw = buffer;
n = NULL;
return 0;
@@ -410,7 +610,7 @@ int config_parse_preferred_src(const char *unit,
}
n->family = f;
- n->prefsrc_addr = buffer;
+ n->prefsrc = buffer;
n = NULL;
return 0;
@@ -484,10 +684,10 @@ int config_parse_destination(const char *unit,
n->family = f;
if (streq(lvalue, "Destination")) {
- n->dst_addr = buffer;
+ n->dst = buffer;
n->dst_prefixlen = prefixlen;
} else if (streq(lvalue, "Source")) {
- n->src_addr = buffer;
+ n->src = buffer;
n->src_prefixlen = prefixlen;
} else
assert_not_reached(lvalue);
@@ -521,9 +721,9 @@ int config_parse_route_priority(const char *unit,
if (r < 0)
return r;
- r = config_parse_unsigned(unit, filename, line, section,
- section_line, lvalue, ltype,
- rvalue, &n->metrics, userdata);
+ r = config_parse_uint32(unit, filename, line, section,
+ section_line, lvalue, ltype,
+ rvalue, &n->priority, userdata);
if (r < 0)
return r;
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index c9972e4933..d0a51838ed 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -30,20 +30,24 @@ struct Route {
Network *network;
unsigned section;
+ Link *link;
+
int family;
unsigned char dst_prefixlen;
unsigned char src_prefixlen;
unsigned char scope;
- uint32_t metrics;
unsigned char protocol; /* RTPROT_* */
unsigned char tos;
- unsigned char priority;
+ uint32_t priority; /* note that ip(8) calls this 'metric' */
unsigned char table;
- union in_addr_union in_addr;
- union in_addr_union dst_addr;
- union in_addr_union src_addr;
- union in_addr_union prefsrc_addr;
+ union in_addr_union gw;
+ union in_addr_union dst;
+ union in_addr_union src;
+ union in_addr_union prefsrc;
+
+ usec_t lifetime;
+ sd_event_source *expire;
LIST_FIELDS(Route, routes);
};
@@ -54,6 +58,14 @@ void route_free(Route *route);
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
+void route_drop(Route *route);
+
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
#define _cleanup_route_free_ _cleanup_(route_freep)
diff --git a/src/network/networkd.c b/src/network/networkd.c
index c03ac69e27..ef394e0c04 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -109,6 +109,12 @@ int main(int argc, char *argv[]) {
goto out;
}
+ r = manager_rtnl_enumerate_routes(m);
+ if (r < 0) {
+ log_error_errno(r, "Could not enumerate routes: %m");
+ goto out;
+ }
+
log_info("Enumeration completed");
sd_notify(false,
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 6c5a9939be..97665fac7a 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -82,8 +82,10 @@ bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
int manager_rtnl_enumerate_addresses(Manager *m);
+int manager_rtnl_enumerate_routes(Manager *m);
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
void manager_dirty(Manager *m);
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 57739d1f3e..432e62dd9f 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -300,8 +300,7 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
percent = strchr(s, '%');
if (percent) {
- r = safe_atoi(percent+1, &ifi);
- if (r < 0 || ifi <= 0) {
+ if (parse_ifindex(percent+1, &ifi) < 0) {
ifi = if_nametoindex(percent+1);
if (ifi <= 0)
return -EINVAL;
@@ -521,7 +520,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'i': {
int ifi;
- if (safe_atoi(optarg, &ifi) >= 0 && ifi > 0)
+ if (parse_ifindex(optarg, &ifi) >= 0)
arg_ifindex = ifi;
else {
ifi = if_nametoindex(optarg);
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index c9919ced67..42e3be3168 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -21,6 +21,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "def.h"
#include "extract-word.h"
#include "parse-util.h"
#include "resolved-conf.h"
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c
index bb00f99ecf..5c45a3ae6c 100644
--- a/src/rfkill/rfkill.c
+++ b/src/rfkill/rfkill.c
@@ -212,7 +212,7 @@ static int load_state(
assert(udev);
assert(event);
- if (!shall_restore_state())
+ if (shall_restore_state() == 0)
return 0;
r = find_device(udev, event, &device);
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 940e393318..a13991a960 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1450,7 +1450,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
"PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
- "SyslogLevelPrefix")) {
+ "SyslogLevelPrefix", "Delegate")) {
r = parse_boolean(eq);
if (r < 0) {
@@ -1789,6 +1789,40 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_close_container(m);
+ } else if (streq(field, "RuntimeDirectory")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s", field, eq);
+
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
} else {
log_error("Unknown assignment %s.", assignment);
return -EINVAL;
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index bbbb3460d4..102c5cc992 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -23,14 +23,15 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
+#include "parse-util.h"
#include "sleep-config.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
-#include "parse-util.h"
#define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0)
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 5e15dfba53..24cfe58cd6 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "conf-files.h"
+#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "hashmap.h"
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index da816e6d0e..70871cf3e6 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -6631,6 +6631,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{}
};
+ const char *p;
int c, r;
assert(argc >= 0);
@@ -6651,15 +6652,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return version();
case 't': {
- const char *word, *state;
- size_t size;
+ if (isempty(optarg))
+ return log_error_errno(r, "--type requires arguments.");
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- _cleanup_free_ char *type;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *type = NULL;
- type = strndup(word, size);
- if (!type)
- return -ENOMEM;
+ r = extract_first_word(&p, &type, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse type: %s", optarg);
+
+ if (r == 0)
+ break;
if (streq(type, "help")) {
help_types();
@@ -6700,18 +6705,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
if (!arg_properties)
return log_oom();
} else {
- const char *word, *state;
- size_t size;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *prop = NULL;
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *prop;
+ r = extract_first_word(&p, &prop, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse property: %s", optarg);
- prop = strndup(word, size);
- if (!prop)
- return log_oom();
+ if (r == 0)
+ break;
- if (strv_consume(&arg_properties, prop) < 0)
+ if (strv_push(&arg_properties, prop) < 0)
return log_oom();
+
+ prop = NULL;
}
}
@@ -6877,15 +6885,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_STATE: {
- const char *word, *state;
- size_t size;
+ if (isempty(optarg))
+ return log_error_errno(r, "--signal requires arguments.");
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+ p = optarg;
+ for(;;) {
_cleanup_free_ char *s = NULL;
- s = strndup(word, size);
- if (!s)
- return log_oom();
+ r = extract_first_word(&p, &s, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse signal: %s", optarg);
+
+ if (r == 0)
+ break;
if (streq(s, "help")) {
help_states();
diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h
deleted file mode 100644
index 80d9fc2862..0000000000
--- a/src/systemd/sd-pppoe.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdpppoefoo
-#define foosdpppoefoo
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
-
- 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 <net/ethernet.h>
-
-#include "sd-event.h"
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-enum {
- SD_PPPOE_EVENT_RUNNING = 0,
- SD_PPPOE_EVENT_STOPPED = 1,
-};
-
-typedef struct sd_pppoe sd_pppoe;
-typedef void (*sd_pppoe_cb_t)(sd_pppoe *ppp, int event, void *userdata);
-
-int sd_pppoe_detach_event(sd_pppoe *ppp);
-int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority);
-int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel);
-int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata);
-int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex);
-int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname);
-int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name);
-int sd_pppoe_start(sd_pppoe *ppp);
-int sd_pppoe_stop(sd_pppoe *ppp);
-sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp);
-sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp);
-int sd_pppoe_new (sd_pppoe **ret);
-
-_SD_END_DECLARATIONS;
-
-#endif
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 36d310b4c4..9a1c88d08e 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -29,6 +29,8 @@
#include "alloc-util.h"
#include "conf-files.h"
#include "copy.h"
+#include "def.h"
+#include "fd-util.h"
#include "fileio-label.h"
#include "formats-util.h"
#include "hashmap.h"
@@ -39,10 +41,9 @@
#include "string-util.h"
#include "strv.h"
#include "uid-range.h"
+#include "user-util.h"
#include "utf8.h"
#include "util.h"
-#include "fd-util.h"
-#include "user-util.h"
typedef enum ItemType {
ADD_USER = 'u',
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index b2d53d3b4f..042be97840 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -530,7 +530,7 @@ static int load_sysv(SysvStub *s) {
if (startswith_no_case(t, "description:")) {
size_t k;
- const const char *j;
+ const char *j;
k = strlen(t);
if (k > 0 && t[k-1] == '\\') {
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index afbaa12e94..e2ec53ee51 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <sys/types.h>
+#include "fileio.h"
#include "fs-util.h"
#include "macro.h"
#include "manager.h"
@@ -147,6 +148,26 @@ static void test_exec_environment(Manager *m) {
test(m, "exec-environment-empty.service", 0, CLD_EXITED);
}
+static void test_exec_environmentfile(Manager *m) {
+ static const char e[] =
+ "VAR1='word1 word2'\n"
+ "VAR2=word3 \n"
+ "# comment1\n"
+ "\n"
+ "; comment2\n"
+ " ; # comment3\n"
+ "line without an equal\n"
+ "VAR3='$word 5 6'\n";
+ int r;
+
+ r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
+ assert_se(r == 0);
+
+ test(m, "exec-environmentfile.service", 0, CLD_EXITED);
+
+ unlink("/tmp/test-exec_environmentfile.conf");
+}
+
static void test_exec_umask(Manager *m) {
test(m, "exec-umask-default.service", 0, CLD_EXITED);
test(m, "exec-umask-0177.service", 0, CLD_EXITED);
@@ -178,6 +199,30 @@ static void test_exec_capabilityboundingset(Manager *m) {
test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
}
+static void test_exec_privatenetwork(Manager *m) {
+ int r;
+
+ r = find_binary("ip", NULL);
+ if (r < 0) {
+ log_error_errno(r, "Skipping test_exec_privatenetwork, could not find ip binary: %m");
+ return;
+ }
+
+ test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
+}
+
+static void test_exec_oomscoreadjust(Manager *m) {
+ test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+ test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
+}
+
+static void test_exec_ioschedulingclass(Manager *m) {
+ test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
+}
+
int main(int argc, char *argv[]) {
test_function_t tests[] = {
test_exec_workingdirectory,
@@ -185,14 +230,18 @@ int main(int argc, char *argv[]) {
test_exec_ignoresigpipe,
test_exec_privatetmp,
test_exec_privatedevices,
+ test_exec_privatenetwork,
test_exec_systemcallfilter,
test_exec_systemcallerrornumber,
test_exec_user,
test_exec_group,
test_exec_environment,
+ test_exec_environmentfile,
test_exec_umask,
test_exec_runtimedirectory,
test_exec_capabilityboundingset,
+ test_exec_oomscoreadjust,
+ test_exec_ioschedulingclass,
NULL,
};
test_function_t *test = NULL;
@@ -209,7 +258,7 @@ int main(int argc, char *argv[]) {
}
assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
- assert_se(set_unit_path(TEST_DIR) >= 0);
+ assert_se(set_unit_path(TEST_DIR "/test-execute/") >= 0);
r = manager_new(MANAGER_USER, true, &m);
if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
diff --git a/src/test/test-path.c b/src/test/test-path.c
index ff0f044958..8302bdd283 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -258,7 +258,7 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- assert_se(set_unit_path(TEST_DIR) >= 0);
+ assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0);
for (test = tests; test && *test; test++) {
int r;
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
new file mode 100644
index 0000000000..25444c794a
--- /dev/null
+++ b/src/test/test-string-util.c
@@ -0,0 +1,61 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 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-util.h"
+
+static void test_string_erase(void) {
+ char *x;
+
+ x = strdupa("");
+ assert_se(streq(string_erase(x), ""));
+
+ x = strdupa("1");
+ assert_se(streq(string_erase(x), "x"));
+
+ x = strdupa("12");
+ assert_se(streq(string_erase(x), "xx"));
+
+ x = strdupa("123");
+ assert_se(streq(string_erase(x), "xxx"));
+
+ x = strdupa("1234");
+ assert_se(streq(string_erase(x), "xxxx"));
+
+ x = strdupa("12345");
+ assert_se(streq(string_erase(x), "xxxxx"));
+
+ x = strdupa("123456");
+ assert_se(streq(string_erase(x), "xxxxxx"));
+
+ x = strdupa("1234567");
+ assert_se(streq(string_erase(x), "xxxxxxx"));
+
+ x = strdupa("12345678");
+ assert_se(streq(string_erase(x), "xxxxxxxx"));
+
+ x = strdupa("123456789");
+ assert_se(streq(string_erase(x), "xxxxxxxxx"));
+}
+
+int main(int argc, char *argv[]) {
+ test_string_erase();
+ return 0;
+}
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 647df4f5c3..f6ed55878c 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -48,6 +48,7 @@
#include "process-util.h"
#include "rm-rf.h"
#include "signal-util.h"
+#include "special.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
@@ -1638,6 +1639,12 @@ cleanup:
assert_se(rmdir(t) >= 0);
}
+static void test_runlevel_to_target(void) {
+ assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
+ assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
+ assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET));
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -1718,6 +1725,7 @@ int main(int argc, char *argv[]) {
test_tempfn();
test_strcmp_ptr();
test_fgetxattrat_fake();
+ test_runlevel_to_target();
return 0;
}
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index be651fc636..001a0f4d41 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -20,11 +20,12 @@
***/
#include "alloc-util.h"
+#include "def.h"
+#include "extract-word.h"
#include "string-util.h"
+#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
#include "timesyncd-server.h"
-#include "timesyncd-conf.h"
-#include "extract-word.h"
int manager_parse_server_string(Manager *m, ServerType type, const char *string) {
ServerName *first;
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 45335425ce..ffae91a3ca 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -45,6 +45,7 @@
#include "chattr-util.h"
#include "conf-files.h"
#include "copy.h"
+#include "def.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"