diff --git a/Makefile.am b/Makefile.am index dde8a7b03c..babc3bbc9e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1705,12 +1705,10 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/nm-sd-utils-shared.c \ shared/systemd/nm-sd-utils-shared.h \ shared/systemd/sd-adapt-shared/architecture.h \ - shared/systemd/sd-adapt-shared/btrfs-util.h \ shared/systemd/sd-adapt-shared/build.h \ - shared/systemd/sd-adapt-shared/cgroup-util.h \ shared/systemd/sd-adapt-shared/copy.h \ shared/systemd/sd-adapt-shared/def.h \ - shared/systemd/sd-adapt-shared/device-nodes.h \ + shared/systemd/sd-adapt-shared/dhcp-server-internal.h \ shared/systemd/sd-adapt-shared/dirent-util.h \ shared/systemd/sd-adapt-shared/errno-list.h \ shared/systemd/sd-adapt-shared/glob-util.h \ @@ -1718,7 +1716,10 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/sd-adapt-shared/ioprio.h \ shared/systemd/sd-adapt-shared/locale-util.h \ shared/systemd/sd-adapt-shared/memfd-util.h \ - shared/systemd/sd-adapt-shared/missing.h \ + shared/systemd/sd-adapt-shared/missing_fs.h \ + shared/systemd/sd-adapt-shared/missing_magic.h \ + shared/systemd/sd-adapt-shared/missing_network.h \ + shared/systemd/sd-adapt-shared/missing_sched.h \ shared/systemd/sd-adapt-shared/missing_syscall.h \ shared/systemd/sd-adapt-shared/missing_timerfd.h \ shared/systemd/sd-adapt-shared/mkdir.h \ @@ -1726,7 +1727,6 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h \ shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h \ shared/systemd/sd-adapt-shared/nulstr-util.h \ - shared/systemd/sd-adapt-shared/procfs-util.h \ shared/systemd/sd-adapt-shared/raw-clone.h \ shared/systemd/sd-adapt-shared/rlimit-util.h \ shared/systemd/sd-adapt-shared/terminal-util.h \ @@ -1775,6 +1775,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/src/basic/mempool.c \ shared/systemd/src/basic/mempool.h \ shared/systemd/src/basic/missing_fcntl.h \ + shared/systemd/src/basic/missing_random.h \ shared/systemd/src/basic/missing_socket.h \ shared/systemd/src/basic/missing_stat.h \ shared/systemd/src/basic/missing_type.h \ @@ -1898,6 +1899,7 @@ src_libnm_systemd_core_la_SOURCES = \ src/systemd/src/systemd/_sd-common.h \ src/systemd/src/systemd/sd-dhcp-client.h \ src/systemd/src/systemd/sd-dhcp-lease.h \ + src/systemd/src/systemd/sd-dhcp-option.h \ src/systemd/src/systemd/sd-dhcp6-client.h \ src/systemd/src/systemd/sd-dhcp6-lease.h \ src/systemd/src/systemd/sd-event.h \ diff --git a/shared/systemd/sd-adapt-shared/btrfs-util.h b/shared/systemd/sd-adapt-shared/dhcp-server-internal.h similarity index 100% rename from shared/systemd/sd-adapt-shared/btrfs-util.h rename to shared/systemd/sd-adapt-shared/dhcp-server-internal.h diff --git a/shared/systemd/sd-adapt-shared/missing.h b/shared/systemd/sd-adapt-shared/missing.h deleted file mode 100644 index d0b460a7ed..0000000000 --- a/shared/systemd/sd-adapt-shared/missing.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -/* dummy header */ - -#include "missing_fcntl.h" -#include "missing_socket.h" -#include "missing_stat.h" -#include "missing_type.h" diff --git a/shared/systemd/sd-adapt-shared/cgroup-util.h b/shared/systemd/sd-adapt-shared/missing_fs.h similarity index 100% rename from shared/systemd/sd-adapt-shared/cgroup-util.h rename to shared/systemd/sd-adapt-shared/missing_fs.h diff --git a/shared/systemd/sd-adapt-shared/device-nodes.h b/shared/systemd/sd-adapt-shared/missing_magic.h similarity index 100% rename from shared/systemd/sd-adapt-shared/device-nodes.h rename to shared/systemd/sd-adapt-shared/missing_magic.h diff --git a/shared/systemd/sd-adapt-shared/format-util.h b/shared/systemd/sd-adapt-shared/missing_network.h similarity index 100% rename from shared/systemd/sd-adapt-shared/format-util.h rename to shared/systemd/sd-adapt-shared/missing_network.h diff --git a/shared/systemd/sd-adapt-shared/procfs-util.h b/shared/systemd/sd-adapt-shared/missing_sched.h similarity index 100% rename from shared/systemd/sd-adapt-shared/procfs-util.h rename to shared/systemd/sd-adapt-shared/missing_sched.h diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c index cd9d3176ca..d16890d97d 100644 --- a/shared/systemd/src/basic/env-util.c +++ b/shared/systemd/src/basic/env-util.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "alloc-util.h" diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c index b584dc42d0..2da25b03d4 100644 --- a/shared/systemd/src/basic/extract-word.c +++ b/shared/systemd/src/basic/extract-word.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "alloc-util.h" diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c index 941053bf65..ea2c161206 100644 --- a/shared/systemd/src/basic/fd-util.c +++ b/shared/systemd/src/basic/fd-util.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -18,7 +17,8 @@ #include "io-util.h" #include "macro.h" #include "memfd-util.h" -#include "missing.h" +#include "missing_fcntl.h" +#include "missing_syscall.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c index 255bcaed1b..3bffa1c5f9 100644 --- a/shared/systemd/src/basic/fileio.c +++ b/shared/systemd/src/basic/fileio.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,6 @@ #include "hexdecoct.h" #include "log.h" #include "macro.h" -#include "missing.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" @@ -314,6 +312,113 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { } #endif /* NM_IGNORED */ +int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) { + _cleanup_free_ char *buf = NULL; + _cleanup_close_ int fd = -1; + struct stat st; + size_t n, size; + int n_retries; + char *p; + + assert(ret_contents); + + /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work + * with two sorts of virtual files. One sort uses "seq_file", and the results of + * the first read are buffered for the second read. The other sort uses "raw" + * reads which always go direct to the device. In the latter case, the content of + * the virtual file must be retrieved with a single read otherwise a second read + * might get the new value instead of finding EOF immediately. That's the reason + * why the usage of fread(3) is prohibited in this case as it always performs a + * second call to read(2) looking for EOF. See issue 13585. */ + + fd = open(filename, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return -errno; + + /* Start size for files in /proc which usually report a file size of 0. */ + size = LINE_MAX / 2; + + /* Limit the number of attempts to read the number of bytes returned by fstat(). */ + n_retries = 3; + + for (;;) { + if (n_retries <= 0) + return -EIO; + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISREG(st.st_mode)) + return -EBADF; + + /* Be prepared for files from /proc which generally report a file size of 0. */ + if (st.st_size > 0) { + size = st.st_size; + n_retries--; + } else + size = size * 2; + + if (size > READ_FULL_BYTES_MAX) + return -E2BIG; + + p = realloc(buf, size + 1); + if (!p) + return -ENOMEM; + buf = TAKE_PTR(p); + + for (;;) { + ssize_t k; + + /* Read one more byte so we can detect whether the content of the + * file has already changed or the guessed size for files from /proc + * wasn't large enough . */ + k = read(fd, buf, size + 1); + if (k >= 0) { + n = k; + break; + } + + if (errno != -EINTR) + return -errno; + } + + /* Consider a short read as EOF */ + if (n <= size) + break; + + /* Hmm... either we read too few bytes from /proc or less likely the content + * of the file might have been changed (and is now bigger) while we were + * processing, let's try again either with a bigger guessed size or the new + * file size. */ + + if (lseek(fd, 0, SEEK_SET) < 0) + return -errno; + } + + if (n < size) { + p = realloc(buf, n + 1); + if (!p) + return -ENOMEM; + buf = TAKE_PTR(p); + } + + if (!ret_size) { + /* Safety check: if the caller doesn't want to know the size of what we + * just read it will rely on the trailing NUL byte. But if there's an + * embedded NUL byte, then we should refuse operation as otherwise + * there'd be ambiguity about what we just read. */ + + if (memchr(buf, 0, n)) + return -EBADMSG; + } else + *ret_size = n; + + buf[n] = 0; + *ret_contents = TAKE_PTR(buf); + + return 0; +} + int read_full_stream_full( FILE *f, const char *filename, @@ -346,9 +451,9 @@ int read_full_stream_full( if (st.st_size > READ_FULL_BYTES_MAX) return -E2BIG; - /* Start with the right file size, but be prepared for files from /proc which generally report a file - * size of 0. Note that we increase the size to read here by one, so that the first read attempt - * already makes us notice the EOF. */ + /* Start with the right file size. Note that we increase the size + * to read here by one, so that the first read attempt already + * makes us notice the EOF. */ if (st.st_size > 0) n_next = st.st_size + 1; @@ -508,7 +613,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin assert(pattern); assert(field); - r = read_full_file(filename, &status, NULL); + r = read_full_virtual_file(filename, &status, NULL); if (r < 0) return r; diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h index 05f6c89da0..31bfef33ac 100644 --- a/shared/systemd/src/basic/fileio.h +++ b/shared/systemd/src/basic/fileio.h @@ -56,6 +56,7 @@ int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **co static inline int read_full_file(const char *filename, char **contents, size_t *size) { return read_full_file_full(filename, 0, contents, size); } +int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size); int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size); static inline int read_full_stream(FILE *f, char **contents, size_t *size) { return read_full_stream_full(f, NULL, 0, contents, size); diff --git a/shared/systemd/src/basic/format-util.c b/shared/systemd/src/basic/format-util.c index 7a3e735ba1..62477f537e 100644 --- a/shared/systemd/src/basic/format-util.c +++ b/shared/systemd/src/basic/format-util.c @@ -2,15 +2,26 @@ #include "nm-sd-adapt-shared.h" -#include - #include "format-util.h" #include "memory-util.h" +#include "stdio-util.h" -char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) { +assert_cc(DECIMAL_STR_MAX(int) + 1 <= IF_NAMESIZE + 1); +char *format_ifname_full(int ifindex, char buf[static IF_NAMESIZE + 1], FormatIfnameFlag flag) { /* Buffer is always cleared */ memzero(buf, IF_NAMESIZE + 1); - return if_indextoname(ifindex, buf); + if (if_indextoname(ifindex, buf)) + return buf; + + if (!FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX)) + return NULL; + + if (FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX_WITH_PERCENT)) + snprintf(buf, IF_NAMESIZE + 1, "%%%d", ifindex); + else + snprintf(buf, IF_NAMESIZE + 1, "%d", ifindex); + + return buf; } char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) { diff --git a/shared/systemd/src/basic/format-util.h b/shared/systemd/src/basic/format-util.h index e0d184a541..59622508a3 100644 --- a/shared/systemd/src/basic/format-util.h +++ b/shared/systemd/src/basic/format-util.h @@ -68,7 +68,15 @@ # error Unknown ino_t size #endif -char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]); +typedef enum { + FORMAT_IFNAME_IFINDEX = 1 << 0, + FORMAT_IFNAME_IFINDEX_WITH_PERCENT = (1 << 1) | FORMAT_IFNAME_IFINDEX, +} FormatIfnameFlag; + +char *format_ifname_full(int ifindex, char buf[static IF_NAMESIZE + 1], FormatIfnameFlag flag); +static inline char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) { + return format_ifname_full(ifindex, buf, 0); +} typedef enum { FORMAT_BYTES_USE_IEC = 1 << 0, diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c index ec987918cc..e30f40fb80 100644 --- a/shared/systemd/src/basic/fs-util.c +++ b/shared/systemd/src/basic/fs-util.c @@ -4,13 +4,9 @@ #include #include -#include #include -#include -#include #include #include -#include #include #include "alloc-util.h" @@ -20,7 +16,9 @@ #include "locale-util.h" #include "log.h" #include "macro.h" -#include "missing.h" +#include "missing_fcntl.h" +#include "missing_fs.h" +#include "missing_syscall.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" @@ -669,6 +667,18 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { } #if 0 /* NM_IGNORED */ +int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) { + + if (inotify_add_watch(fd, pathname, mask) < 0) { + if (errno == ENOSPC) + return log_error_errno(errno, "Failed to add a watch for %s: inotify watch limit reached", pathname); + + return log_error_errno(errno, "Failed to add a watch for %s: %m", pathname); + } + + return 0; +} + static bool unsafe_transition(const struct stat *a, const struct stat *b) { /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files @@ -707,7 +717,7 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) { n1, path); } -int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) { +int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) { _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL; _cleanup_close_ int fd = -1; unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */ @@ -719,10 +729,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, assert(path); /* Either the file may be missing, or we return an fd to the final object, but both make no sense */ - if (FLAGS_SET(flags, CHASE_NONEXISTENT | CHASE_OPEN)) + if ((flags & CHASE_NONEXISTENT) && ret_fd) return -EINVAL; - if (FLAGS_SET(flags, CHASE_STEP | CHASE_OPEN)) + if ((flags & CHASE_STEP) && ret_fd) return -EINVAL; if (isempty(path)) @@ -748,17 +758,17 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * function what to do when encountering a symlink with an absolute path as directory: prefix it by the * specified path. * - * There are three ways to invoke this function: + * There are five ways to invoke this function: * - * 1. Without CHASE_STEP or CHASE_OPEN: in this case the path is resolved and the normalized path is returned - * in `ret`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0 is returned if the file - * doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is returned if the destination was - * found, -ENOENT if it wasn't. + * 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is + * returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0 + * is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is + * returned if the destination was found, -ENOENT if it wasn't. * - * 2. With CHASE_OPEN: in this case the destination is opened after chasing it as O_PATH and this file + * 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file * descriptor is returned as return value. This is useful to open files relative to some root * directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using - * fd_reopen() or such) before it can be used for reading/writing. CHASE_OPEN may not be combined with + * fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with * CHASE_NONEXISTENT. * * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first @@ -774,21 +784,21 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization * is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of * the mount point is emitted. - * */ /* A root directory of "/" or "" is identical to none */ if (empty_or_root(original_root)) original_root = NULL; - if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) { - /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set + if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) { + /* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set * and doesn't care about any of the other special features we provide either. */ r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0)); if (r < 0) return -errno; - return r; + *ret_fd = r; + return 0; } if (original_root) { @@ -797,7 +807,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return r; if (flags & CHASE_PREFIX_ROOT) { - /* We don't support relative paths in combination with a root directory */ if (!path_is_absolute(path)) return -EINVAL; @@ -942,7 +951,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) { char *joined; - _cleanup_free_ char *destination = NULL; /* This is a symlink, in this case read the destination. But let's make sure we don't follow @@ -1028,15 +1036,15 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - if (ret) - *ret = TAKE_PTR(done); + if (ret_path) + *ret_path = TAKE_PTR(done); - if (flags & CHASE_OPEN) { - /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by - * opening /proc/self/fd/xyz. */ + if (ret_fd) { + /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a + * proper fd by opening /proc/self/fd/xyz. */ assert(fd >= 0); - return TAKE_FD(fd); + *ret_fd = TAKE_FD(fd); } if (flags & CHASE_STEP) @@ -1045,14 +1053,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return exists; chased_one: - if (ret) { + if (ret_path) { char *c; c = strjoin(strempty(done), todo); if (!c) return -ENOMEM; - *ret = c; + *ret_path = c; } return 0; @@ -1081,9 +1089,10 @@ int chase_symlinks_and_open( return r; } - path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); - if (path_fd < 0) - return path_fd; + r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd); + if (r < 0) + return r; + assert(path_fd >= 0); r = fd_reopen(path_fd, open_flags); if (r < 0) @@ -1106,6 +1115,7 @@ int chase_symlinks_and_opendir( _cleanup_close_ int path_fd = -1; _cleanup_free_ char *p = NULL; DIR *d; + int r; if (!ret_dir) return -EINVAL; @@ -1122,9 +1132,10 @@ int chase_symlinks_and_opendir( return 0; } - path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); - if (path_fd < 0) - return path_fd; + r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd); + if (r < 0) + return r; + assert(path_fd >= 0); xsprintf(procfs_path, "/proc/self/fd/%i", path_fd); d = opendir(procfs_path); @@ -1143,10 +1154,12 @@ int chase_symlinks_and_stat( const char *root, unsigned chase_flags, char **ret_path, - struct stat *ret_stat) { + struct stat *ret_stat, + int *ret_fd) { _cleanup_close_ int path_fd = -1; _cleanup_free_ char *p = NULL; + int r; assert(path); assert(ret_stat); @@ -1162,18 +1175,18 @@ int chase_symlinks_and_stat( return 1; } - path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); - if (path_fd < 0) - return path_fd; + r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd); + if (r < 0) + return r; + assert(path_fd >= 0); if (fstat(path_fd, ret_stat) < 0) return -errno; if (ret_path) *ret_path = TAKE_PTR(p); - - if (chase_flags & CHASE_OPEN) - return TAKE_FD(path_fd); + if (ret_fd) + *ret_fd = TAKE_FD(path_fd); return 1; } diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h index 1f0bdd95b3..78d68be9fd 100644 --- a/shared/systemd/src/basic/fs-util.h +++ b/shared/systemd/src/basic/fs-util.h @@ -72,29 +72,28 @@ union inotify_event_buffer { }; int inotify_add_watch_fd(int fd, int what, uint32_t mask); +int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask); enum { CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */ CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */ CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */ CHASE_SAFE = 1 << 3, /* Return EPERM if we ever traverse from unprivileged to privileged files or directories */ - CHASE_OPEN = 1 << 4, /* Return an O_PATH object to the final component */ - CHASE_TRAIL_SLASH = 1 << 5, /* Any trailing slash will be preserved */ - CHASE_STEP = 1 << 6, /* Just execute a single step of the normalization */ - CHASE_NOFOLLOW = 1 << 7, /* Do not follow the path's right-most compontent. With CHASE_OPEN, when - * the path's right-most component refers to symlink, return O_PATH fd of - * the symlink. */ - CHASE_WARN = 1 << 8, /* Emit an appropriate warning when an error is encountered */ + CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */ + CHASE_STEP = 1 << 5, /* Just execute a single step of the normalization */ + CHASE_NOFOLLOW = 1 << 6, /* Do not follow the path's right-most compontent. With ret_fd, when the path's + * right-most component refers to symlink, return O_PATH fd of the symlink. */ + CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered */ }; /* How many iterations to execute before returning -ELOOP */ #define CHASE_SYMLINKS_MAX 32 -int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); +int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd); int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path); int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir); -int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat); +int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd); /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ static inline void rmdir_and_free(char *p) { diff --git a/shared/systemd/src/basic/hash-funcs.c b/shared/systemd/src/basic/hash-funcs.c index 03695098a6..1b0d129237 100644 --- a/shared/systemd/src/basic/hash-funcs.c +++ b/shared/systemd/src/basic/hash-funcs.c @@ -55,11 +55,7 @@ void path_hash_func(const char *q, struct siphash *state) { } } -int path_compare_func(const char *a, const char *b) { - return path_compare(a, b); -} - -DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare_func); +DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare); #endif /* NM_IGNORED */ void trivial_hash_func(const void *p, struct siphash *state) { diff --git a/shared/systemd/src/basic/hash-funcs.h b/shared/systemd/src/basic/hash-funcs.h index 0d2d428389..7bb5d1cd02 100644 --- a/shared/systemd/src/basic/hash-funcs.h +++ b/shared/systemd/src/basic/hash-funcs.h @@ -79,7 +79,6 @@ extern const struct hash_ops string_hash_ops; extern const struct hash_ops string_hash_ops_free_free; void path_hash_func(const char *p, struct siphash *state); -int path_compare_func(const char *a, const char *b) _pure_; extern const struct hash_ops path_hash_ops; /* This will compare the passed pointers directly, and will not dereference them. This is hence not useful for strings diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c index b1ae08cdf0..1aa009478a 100644 --- a/shared/systemd/src/basic/hashmap.c +++ b/shared/systemd/src/basic/hashmap.c @@ -5,7 +5,6 @@ #include #include #include -#include #include "alloc-util.h" #include "fileio.h" @@ -13,7 +12,7 @@ #include "macro.h" #include "memory-util.h" #include "mempool.h" -#include "missing.h" +#include "missing_syscall.h" #include "process-util.h" #include "random-util.h" #include "set.h" diff --git a/shared/systemd/src/basic/hostname-util.c b/shared/systemd/src/basic/hostname-util.c index 60a94b9686..00a92cb79a 100644 --- a/shared/systemd/src/basic/hostname-util.c +++ b/shared/systemd/src/basic/hostname-util.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c index 9669c463d1..4f57f04477 100644 --- a/shared/systemd/src/basic/io-util.c +++ b/shared/systemd/src/basic/io-util.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "io-util.h" diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h index 43c513265e..fc733366b3 100644 --- a/shared/systemd/src/basic/macro.h +++ b/shared/systemd/src/basic/macro.h @@ -316,17 +316,18 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { extern void __coverity_panic__(void); -static inline int __coverity_check__(int condition) { +static inline void __coverity_check__(int condition) { + if (!condition) + __coverity_panic__(); +} + +static inline int __coverity_check_and_return__(int condition) { return condition; } -#define assert_message_se(expr, message) \ - do { \ - if (__coverity_check__(!(expr))) \ - __coverity_panic__(); \ - } while (false) +#define assert_message_se(expr, message) __coverity_check__(!!(expr)) -#define assert_log(expr, message) __coverity_check__(!!(expr)) +#define assert_log(expr, message) __coverity_check_and_return__(!!(expr)) #else /* ! __COVERITY__ */ diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h index 9cb8ac3c10..46a6907a0c 100644 --- a/shared/systemd/src/basic/memory-util.h +++ b/shared/systemd/src/basic/memory-util.h @@ -11,6 +11,7 @@ size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) +#define PAGE_ALIGN_DOWN(l) (l & ~(page_size() - 1)) /* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ static inline void memcpy_safe(void *dst, const void *src, size_t n) { diff --git a/shared/systemd/src/basic/missing_random.h b/shared/systemd/src/basic/missing_random.h new file mode 100644 index 0000000000..2e76031b32 --- /dev/null +++ b/shared/systemd/src/basic/missing_random.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#if USE_SYS_RANDOM_H +# include +#else +# include +#endif + +#ifndef GRND_NONBLOCK +#define GRND_NONBLOCK 0x0001 +#endif + +#ifndef GRND_RANDOM +#define GRND_RANDOM 0x0002 +#endif diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c index 76ef6e093b..96cc43a2ae 100644 --- a/shared/systemd/src/basic/parse-util.c +++ b/shared/systemd/src/basic/parse-util.c @@ -5,11 +5,9 @@ #include #include #include -#include #include #include #include -#include #include #include "alloc-util.h" @@ -17,7 +15,7 @@ #include "extract-word.h" #include "locale-util.h" #include "macro.h" -#include "missing.h" +#include "missing_network.h" #include "parse-util.h" #include "process-util.h" #include "stat-util.h" diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c index e39656bc07..5bcc35e5dd 100644 --- a/shared/systemd/src/basic/path-util.c +++ b/shared/systemd/src/basic/path-util.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include /* When we include libgen.h because we need dirname() we immediately @@ -22,7 +20,6 @@ #include "glob-util.h" #include "log.h" #include "macro.h" -#include "missing.h" #include "nulstr-util.h" #include "parse-util.h" #include "path-util.h" @@ -276,7 +273,7 @@ char **path_strv_resolve(char **l, const char *root) { } else t = *s; - r = chase_symlinks(t, root, 0, &u); + r = chase_symlinks(t, root, 0, &u, NULL); if (r == -ENOENT) { if (root) { u = TAKE_PTR(orig); @@ -658,7 +655,9 @@ int find_binary(const char *name, char **ret) { return 0; } - last_error = -errno; + /* PATH entries which we don't have access to are ignored, as per tradition. */ + if (errno != EACCES) + last_error = -errno; } return last_error; diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h index 8314b64515..88aef2f377 100644 --- a/shared/systemd/src/basic/path-util.h +++ b/shared/systemd/src/basic/path-util.h @@ -12,42 +12,38 @@ #if 0 /* NM_IGNORED */ #define PATH_SPLIT_SBIN_BIN(x) x "sbin:" x "bin" -#define PATH_SPLIT_BIN_SBIN(x) x "bin:" x "sbin" #define PATH_SPLIT_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0" #define PATH_NORMAL_SBIN_BIN(x) x "bin" -#define PATH_NORMAL_BIN_SBIN(x) x "bin" #define PATH_NORMAL_SBIN_BIN_NULSTR(x) x "bin\0" #if HAVE_SPLIT_BIN # define PATH_SBIN_BIN(x) PATH_SPLIT_SBIN_BIN(x) -# define PATH_BIN_SBIN(x) PATH_SPLIT_BIN_SBIN(x) # define PATH_SBIN_BIN_NULSTR(x) PATH_SPLIT_SBIN_BIN_NULSTR(x) #else # define PATH_SBIN_BIN(x) PATH_NORMAL_SBIN_BIN(x) -# define PATH_BIN_SBIN(x) PATH_NORMAL_BIN_SBIN(x) # define PATH_SBIN_BIN_NULSTR(x) PATH_NORMAL_SBIN_BIN_NULSTR(x) #endif #define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/") -#define DEFAULT_USER_PATH_NORMAL PATH_BIN_SBIN("/usr/local/") ":" PATH_BIN_SBIN("/usr/") #define DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/") #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/") -#define DEFAULT_USER_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_BIN_SBIN("/") #define DEFAULT_PATH_SPLIT_USR_NULSTR DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/") #define DEFAULT_PATH_COMPAT PATH_SPLIT_SBIN_BIN("/usr/local/") ":" PATH_SPLIT_SBIN_BIN("/usr/") ":" PATH_SPLIT_SBIN_BIN("/") #if HAVE_SPLIT_USR # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR -# define DEFAULT_USER_PATH DEFAULT_USER_PATH_SPLIT_USR # define DEFAULT_PATH_NULSTR DEFAULT_PATH_SPLIT_USR_NULSTR #else # define DEFAULT_PATH DEFAULT_PATH_NORMAL -# define DEFAULT_USER_PATH DEFAULT_USER_PATH_NORMAL # define DEFAULT_PATH_NULSTR DEFAULT_PATH_NORMAL_NULSTR #endif #endif /* NM_IGNORED */ +#ifndef DEFAULT_USER_PATH +# define DEFAULT_USER_PATH DEFAULT_PATH +#endif + bool is_path(const char *p) _pure_; int path_split_and_make_absolute(const char *p, char ***ret); bool path_is_absolute(const char *p) _pure_; diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index 317815fe05..fd771ef0b0 100644 --- a/shared/systemd/src/basic/process-util.c +++ b/shared/systemd/src/basic/process-util.c @@ -6,11 +6,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -37,7 +35,8 @@ #include "log.h" #include "macro.h" #include "memory-util.h" -#include "missing.h" +#include "missing_sched.h" +#include "missing_syscall.h" #include "namespace-util.h" #include "process-util.h" #include "raw-clone.h" diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h index 20f663e232..66853c6e8d 100644 --- a/shared/systemd/src/basic/process-util.h +++ b/shared/systemd/src/basic/process-util.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include #include #include #include diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c index b858baa5f9..86917ca3c7 100644 --- a/shared/systemd/src/basic/random-util.c +++ b/shared/systemd/src/basic/random-util.c @@ -19,17 +19,12 @@ # include #endif -#if USE_SYS_RANDOM_H -# include -#else -# include -#endif - #include "alloc-util.h" #include "fd-util.h" #include "fileio.h" #include "io-util.h" -#include "missing.h" +#include "missing_random.h" +#include "missing_syscall.h" #include "parse-util.h" #include "random-util.h" #include "siphash24.h" diff --git a/shared/systemd/src/basic/set.h b/shared/systemd/src/basic/set.h index 2bb26c68b8..5f1956177e 100644 --- a/shared/systemd/src/basic/set.h +++ b/shared/systemd/src/basic/set.h @@ -102,8 +102,8 @@ static inline void *set_steal_first(Set *s) { /* no set_steal_first_key */ /* no set_first_key */ -static inline void *set_first(Set *s) { - return internal_hashmap_first_key_and_value(HASHMAP_BASE(s), false, NULL); +static inline void *set_first(const Set *s) { + return internal_hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL); } /* no set_next */ diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c index b822ed03ff..cded4545c1 100644 --- a/shared/systemd/src/basic/socket-util.c +++ b/shared/systemd/src/basic/socket-util.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include "alloc-util.h" @@ -25,7 +25,7 @@ #include "log.h" #include "macro.h" #include "memory-util.h" -#include "missing.h" +#include "missing_socket.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c index c9837fa1cf..071050f2e4 100644 --- a/shared/systemd/src/basic/stat-util.c +++ b/shared/systemd/src/basic/stat-util.c @@ -2,12 +2,9 @@ #include "nm-sd-adapt-shared.h" -#include #include #include -#include #include -#include #include #include #include @@ -17,7 +14,8 @@ #include "fd-util.h" #include "fs-util.h" #include "macro.h" -#include "missing.h" +#include "missing_fs.h" +#include "missing_magic.h" #include "parse-util.h" #include "stat-util.h" #include "string-util.h" @@ -340,7 +338,7 @@ int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) { if (r < 0) return r; - return chase_symlinks(p, NULL, 0, ret); + return chase_symlinks(p, NULL, 0, ret, NULL); } int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) { diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h index 42fe4f4315..2d3cf81435 100644 --- a/shared/systemd/src/basic/string-table.h +++ b/shared/systemd/src/basic/string-table.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "macro.h" diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c index 2d34603ecb..3d2feb181b 100644 --- a/shared/systemd/src/basic/string-util.c +++ b/shared/systemd/src/basic/string-util.c @@ -7,7 +7,6 @@ #include #include #include -#include #include "alloc-util.h" #include "escape.h" @@ -750,7 +749,7 @@ static void advance_offsets( } char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { - const char *i, *begin = NULL; + const char *begin = NULL; enum { STATE_OTHER, STATE_ESCAPE, @@ -758,7 +757,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { STATE_CSO, } state = STATE_OTHER; char *obuf = NULL; - size_t osz = 0, isz, shift[2] = {}; + size_t osz = 0, isz, shift[2] = {}, n_carriage_returns = 0; FILE *f; assert(ibuf); @@ -769,6 +768,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { * 1. Replaces TABs by 8 spaces * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences + * 4. Strip trailing \r characters (since they would "move the cursor", but have no + * other effect). * * Everything else will be left as it is. In particular other ANSI sequences are left as they are, as * are any other special characters. Truncated ANSI sequences are left-as is too. This call is @@ -784,14 +785,24 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { if (!f) return NULL; - for (i = *ibuf; i < *ibuf + isz + 1; i++) { + for (const char *i = *ibuf; i < *ibuf + isz + 1; i++) { switch (state) { case STATE_OTHER: if (i >= *ibuf + isz) /* EOT */ break; - else if (*i == '\x1B') + + if (*i == '\r') { + n_carriage_returns++; + break; + } else if (*i == '\n') + /* Ignore carriage returns before new line */ + n_carriage_returns = 0; + for (; n_carriage_returns > 0; n_carriage_returns--) + fputc('\r', f); + + if (*i == '\x1B') state = STATE_ESCAPE; else if (*i == '\t') { fputs(" ", f); @@ -802,6 +813,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { break; case STATE_ESCAPE: + assert(n_carriage_returns == 0); + if (i >= *ibuf + isz) { /* EOT */ fputc('\x1B', f); advance_offsets(i - *ibuf, highlight, shift, 1); @@ -822,6 +835,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { break; case STATE_CSI: + assert(n_carriage_returns == 0); if (i >= *ibuf + isz || /* EOT … */ !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */ @@ -836,6 +850,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { break; case STATE_CSO: + assert(n_carriage_returns == 0); if (i >= *ibuf + isz || /* EOT … */ (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */ @@ -855,7 +870,6 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { fclose(f); return mfree(obuf); } - fclose(f); free_and_replace(*ibuf, obuf); diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h index 76767afcac..04cc82b386 100644 --- a/shared/systemd/src/basic/string-util.h +++ b/shared/systemd/src/basic/string-util.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include #include #include #include @@ -45,6 +44,22 @@ static inline const char *strna(const char *s) { return s ?: "n/a"; } +static inline const char* yes_no(bool b) { + return b ? "yes" : "no"; +} + +static inline const char* true_false(bool b) { + return b ? "true" : "false"; +} + +static inline const char* one_zero(bool b) { + return b ? "1" : "0"; +} + +static inline const char* enable_disable(bool b) { + return b ? "enable" : "disable"; +} + static inline bool isempty(const char *p) { return !p || !p[0]; } diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c index ba23178a40..aa46713264 100644 --- a/shared/systemd/src/basic/strv.c +++ b/shared/systemd/src/basic/strv.c @@ -7,7 +7,6 @@ #include #include #include -#include #include "alloc-util.h" #include "escape.h" diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c index dd86f40f30..4411127a1d 100644 --- a/shared/systemd/src/basic/time-util.c +++ b/shared/systemd/src/basic/time-util.c @@ -6,9 +6,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -839,8 +837,12 @@ int parse_timestamp(const char *t, usec_t *usec) { } if (r == 0) { bool with_tz = true; + char *colon_tz; - if (setenv("TZ", tz, 1) != 0) { + /* tzset(3) says $TZ should be prefixed with ":" if we reference timezone files */ + colon_tz = strjoina(":", tz); + + if (setenv("TZ", colon_tz, 1) != 0) { shared->return_value = negative_errno(); _exit(EXIT_FAILURE); } @@ -1265,6 +1267,7 @@ int get_timezones(char ***ret) { } strv_sort(zones); + strv_uniq(zones); } else if (errno != ENOENT) return -errno; @@ -1285,6 +1288,10 @@ bool timezone_is_valid(const char *name, int log_level) { if (isempty(name)) return false; + /* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */ + if (streq(name, "UTC")) + return true; + if (name[0] == '/') return false; @@ -1391,13 +1398,22 @@ bool clock_supported(clockid_t clock) { } #if 0 /* NM_IGNORED */ -int get_timezone(char **tz) { +int get_timezone(char **ret) { _cleanup_free_ char *t = NULL; const char *e; char *z; int r; r = readlink_malloc("/etc/localtime", &t); + if (r == -ENOENT) { + /* If the symlink does not exist, assume "UTC", like glibc does*/ + z = strdup("UTC"); + if (!z) + return -ENOMEM; + + *ret = z; + return 0; + } if (r < 0) return r; /* returns EINVAL if not a symlink */ @@ -1412,7 +1428,7 @@ int get_timezone(char **tz) { if (!z) return -ENOMEM; - *tz = z; + *ret = z; return 0; } diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c index c02ce3df78..d8a689e08d 100644 --- a/shared/systemd/src/basic/tmpfile-util.c +++ b/shared/systemd/src/basic/tmpfile-util.c @@ -2,7 +2,6 @@ #include "nm-sd-adapt-shared.h" -#include #include #include "alloc-util.h" diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c index 3c51fa1ff6..ba28e12968 100644 --- a/shared/systemd/src/basic/utf8.c +++ b/shared/systemd/src/basic/utf8.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "alloc-util.h" #include "gunicode.h" diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c index 23aa6b2623..8a3f95dc1e 100644 --- a/shared/systemd/src/basic/util.c +++ b/shared/systemd/src/basic/util.c @@ -2,50 +2,23 @@ #include "nm-sd-adapt-shared.h" -#include #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include "alloc-util.h" -#include "btrfs-util.h" #include "build.h" -#include "def.h" -#include "device-nodes.h" #include "dirent-util.h" #include "env-file.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" -#include "format-util.h" -#include "hashmap.h" #include "hostname-util.h" #include "log.h" #include "macro.h" -#include "missing.h" #include "parse-util.h" -#include "path-util.h" -#include "process-util.h" -#include "procfs-util.h" -#include "set.h" -#include "signal-util.h" #include "stat-util.h" #include "string-util.h" -#include "strv.h" -#include "time-util.h" -#include "umask-util.h" -#include "user-util.h" #include "util.h" #include "virt.h" diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h index 25e6ab8112..6fc7480fcb 100644 --- a/shared/systemd/src/basic/util.h +++ b/shared/systemd/src/basic/util.h @@ -5,22 +5,6 @@ #include "macro.h" -static inline const char* yes_no(bool b) { - return b ? "yes" : "no"; -} - -static inline const char* true_false(bool b) { - return b ? "true" : "false"; -} - -static inline const char* one_zero(bool b) { - return b ? "1" : "0"; -} - -static inline const char* enable_disable(bool b) { - return b ? "enable" : "disable"; -} - extern int saved_argc; extern char **saved_argv; diff --git a/shared/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c index 92543ebe9b..9bba7359f9 100644 --- a/shared/systemd/src/shared/dns-domain.c +++ b/shared/systemd/src/shared/dns-domain.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "alloc-util.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index e0269b5456..6a803d7b05 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -15,11 +15,21 @@ #include "dhcp-protocol.h" #include "socket-util.h" +typedef struct sd_dhcp_option { + unsigned n_ref; + + uint8_t option; + void *data; + size_t length; +} sd_dhcp_option; + +extern const struct hash_ops dhcp_option_hash_ops; + int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, size_t mac_addr_len, uint16_t arp_type, uint16_t port); -int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port); +int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type); int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len); int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, @@ -41,7 +51,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len); void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, uint16_t source, be32_t destination_addr, - uint16_t destination, uint16_t len); + uint16_t destination, uint16_t len, int ip_service_type); int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port); diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 858fe57ca9..1f01ece14c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -148,7 +147,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, bcast_addr, ð_mac, arp_type, dhcp_hlen, port); } -int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { +int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) { union sockaddr_union src = { .in.sin_family = AF_INET, .in.sin_port = htobe16(port), @@ -161,7 +160,11 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { if (s < 0) return -errno; - r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6); + if (ip_service_type >= 0) + r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type); + else + r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6); + if (r < 0) return r; diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 7690449194..4919387939 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -8,10 +8,10 @@ #include #include #include -#include #include "alloc-util.h" #include "dhcp-internal.h" +#include "dhcp-server-internal.h" #include "memory-util.h" #include "strv.h" #include "utf8.h" @@ -79,6 +79,32 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, *offset += 3 + optlen; break; + case SD_DHCP_OPTION_VENDOR_SPECIFIC: { + OrderedHashmap *s = (OrderedHashmap *) optval; + struct sd_dhcp_option *p; + size_t l = 0; + Iterator i; + + ORDERED_HASHMAP_FOREACH(p, s, i) + l += p->length + 2; + + if (*offset + l + 2 > size) + return -ENOBUFS; + + options[*offset] = code; + options[*offset + 1] = l; + + *offset += 2; + + ORDERED_HASHMAP_FOREACH(p, s, i) { + options[*offset] = p->option; + options[*offset + 1] = p->length; + memcpy(&options[*offset + 2], p->data, p->length); + *offset += 2 + p->length; + } + + break; + } default: if (*offset + 2 + optlen > size) return -ENOBUFS; @@ -291,3 +317,43 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c return message_type; } + +static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) { + if (!i) + return NULL; + + free(i->data); + return mfree(i); +} + +int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) { + assert_return(ret, -EINVAL); + assert_return(length == 0 || data, -EINVAL); + + _cleanup_free_ void *q = memdup(data, length); + if (!q) + return -ENOMEM; + + sd_dhcp_option *p = new(sd_dhcp_option, 1); + if (!p) + return -ENOMEM; + + *p = (sd_dhcp_option) { + .n_ref = 1, + .option = option, + .length = length, + .data = TAKE_PTR(q), + }; + + *ret = TAKE_PTR(p); + return 0; +} + +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free); +DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + dhcp_option_hash_ops, + void, + trivial_hash_func, + trivial_compare_func, + sd_dhcp_option, + sd_dhcp_option_unref); diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 9e565e2887..2062be91c8 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -77,12 +77,15 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, uint16_t source_port, be32_t destination_addr, - uint16_t destination_port, uint16_t len) { + uint16_t destination_port, uint16_t len, int ip_service_type) { packet->ip.version = IPVERSION; packet->ip.ihl = DHCP_IP_SIZE / 4; packet->ip.tot_len = htobe16(len); - packet->ip.tos = IPTOS_CLASS_CS6; + if (ip_service_type >= 0) + packet->ip.tos = ip_service_type; + else + packet->ip.tos = IPTOS_CLASS_CS6; packet->ip.protocol = IPPROTO_UDP; packet->ip.saddr = source_addr; diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index f28ba68dd1..517e357d3d 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -85,7 +85,7 @@ typedef struct DHCP6IA DHCP6IA; int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia); -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd); +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index 73c195a71a..d43680a561 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index 562a34b53a..bb4c4d9130 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -7,7 +7,6 @@ #include #include -#include #include "sd-dhcp6-client.h" @@ -170,9 +169,10 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { return r; } -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) { DHCP6Option *option = (DHCP6Option *)buf; size_t i = sizeof(*option) + sizeof(pd->ia_pd); + DHCP6PDPrefixOption *prefix_opt; DHCP6Address *prefix; assert_return(buf, -EINVAL); @@ -185,10 +185,7 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { option->code = htobe16(SD_DHCP6_OPTION_IA_PD); memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd)); - LIST_FOREACH(addresses, prefix, pd->addresses) { - DHCP6PDPrefixOption *prefix_opt; - if (len < i + sizeof(*prefix_opt)) return -ENOBUFS; @@ -196,9 +193,19 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, - sizeof(struct iapdprefix)); + memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix)); + i += sizeof(*prefix_opt); + } + if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) { + if (len < i + sizeof(*prefix_opt)) + return -ENOBUFS; + + prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; + prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); + prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); + + memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix)); i += sizeof(*prefix_opt); } diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index 530af0347d..238d718bfb 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -10,7 +10,7 @@ #include "lldp-internal.h" #include "lldp-neighbor.h" #include "memory-util.h" -#include "missing.h" +#include "missing_network.h" #include "unaligned.h" static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) { diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index 5ba9f081ea..f4764dd145 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -7,7 +7,7 @@ #include "fd-util.h" #include "lldp-network.h" -#include "missing.h" +#include "missing_network.h" #include "socket-util.h" int lldp_network_bind_raw_socket(int ifindex) { diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 07d459f6fe..7d22e7545c 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -22,6 +22,7 @@ #include "parse-util.h" #include "siphash24.h" #include "socket-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "utf8.h" @@ -139,15 +140,38 @@ static int net_condition_test_property(char * const *match_property, sd_device * return true; } +static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { + [NL80211_IFTYPE_ADHOC] = "ad-hoc", + [NL80211_IFTYPE_STATION] = "station", + [NL80211_IFTYPE_AP] = "ap", + [NL80211_IFTYPE_AP_VLAN] = "ap-vlan", + [NL80211_IFTYPE_WDS] = "wds", + [NL80211_IFTYPE_MONITOR] = "monitor", + [NL80211_IFTYPE_MESH_POINT] = "mesh-point", + [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client", + [NL80211_IFTYPE_P2P_GO] = "p2p-go", + [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device", + [NL80211_IFTYPE_OCB] = "ocb", + [NL80211_IFTYPE_NAN] = "nan", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); + bool net_match_config(Set *match_mac, char * const *match_paths, char * const *match_drivers, char * const *match_types, char * const *match_names, char * const *match_property, + char * const *match_wifi_iftype, + char * const *match_ssid, + Set *match_bssid, sd_device *device, const struct ether_addr *dev_mac, - const char *dev_name) { + const char *dev_name, + enum nl80211_iftype wifi_iftype, + const char *ssid, + const struct ether_addr *bssid) { const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str; @@ -181,6 +205,15 @@ bool net_match_config(Set *match_mac, if (!net_condition_test_property(match_property, device)) return false; + if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(wifi_iftype))) + return false; + + if (!net_condition_test_strv(match_ssid, ssid)) + return false; + + if (match_bssid && (!bssid || !set_contains(match_bssid, bssid))) + return false; + return true; } diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 487421fbd9..2eb0cba5b7 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include #include #include "sd-device.h" @@ -21,9 +22,15 @@ bool net_match_config(Set *match_mac, char * const *match_type, char * const *match_name, char * const *match_property, + char * const *match_wifi_iftype, + char * const *match_ssid, + Set *match_bssid, sd_device *device, const struct ether_addr *dev_mac, - const char *dev_name); + const char *dev_name, + enum nl80211_iftype wifi_iftype, + const char *ssid, + const struct ether_addr *bssid); CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index cbea676dd7..0266161d78 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -92,6 +91,7 @@ struct sd_dhcp_client { usec_t start_time; uint64_t attempt; uint64_t max_attempts; + OrderedHashmap *options; usec_t request_sent; sd_event_source *timeout_t1; sd_event_source *timeout_t2; @@ -100,6 +100,7 @@ struct sd_dhcp_client { void *userdata; sd_dhcp_lease *lease; usec_t start_delay; + int ip_service_type; }; static const uint8_t default_req_opts[] = { @@ -234,6 +235,7 @@ int sd_dhcp_client_set_mac( DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; + int r; assert_return(client, -EINVAL); assert_return(addr, -EINVAL); @@ -261,8 +263,11 @@ int sd_dhcp_client_set_mac( client->mac_addr_len = addr_len; client->arp_type = arp_type; - if (need_restart && client->state != DHCP_STATE_STOPPED) - sd_dhcp_client_start(client); + if (need_restart && client->state != DHCP_STATE_STOPPED) { + r = sd_dhcp_client_start(client); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); + } return 0; } @@ -298,6 +303,7 @@ int sd_dhcp_client_set_client_id( DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; + int r; assert_return(client, -EINVAL); assert_return(data, -EINVAL); @@ -331,8 +337,11 @@ int sd_dhcp_client_set_client_id( memcpy(&client->client_id.raw.data, data, data_len); client->client_id_len = data_len + sizeof (client->client_id.type); - if (need_restart && client->state != DHCP_STATE_STOPPED) - sd_dhcp_client_start(client); + if (need_restart && client->state != DHCP_STATE_STOPPED) { + r = sd_dhcp_client_start(client); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); + } return 0; } @@ -363,7 +372,7 @@ static int dhcp_client_set_iaid_duid_internal( if (duid) { r = dhcp_validate_duid_len(duid_type, duid_len, true); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to validate length of DUID: %m"); } zero(client->client_id); @@ -378,7 +387,7 @@ static int dhcp_client_set_iaid_duid_internal( true, &client->client_id.ns.iaid); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to set IAID: %m"); } } @@ -390,32 +399,32 @@ static int dhcp_client_set_iaid_duid_internal( switch (duid_type) { case DUID_TYPE_LLT: if (client->mac_addr_len == 0) - return -EOPNOTSUPP; + return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set."); r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m"); break; case DUID_TYPE_EN: r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m"); break; case DUID_TYPE_LL: if (client->mac_addr_len == 0) - return -EOPNOTSUPP; + return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set."); r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m"); break; case DUID_TYPE_UUID: r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m"); break; default: - return -EINVAL; + return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type"); } client->client_id_len = sizeof(client->client_id.type) + len + @@ -424,7 +433,9 @@ static int dhcp_client_set_iaid_duid_internal( if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : ""); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - sd_dhcp_client_start(client); + r = sd_dhcp_client_start(client); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); } return 0; @@ -534,6 +545,24 @@ int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempt return 0; } +int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) { + int r; + + assert_return(client, -EINVAL); + assert_return(v, -EINVAL); + + r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops); + if (r < 0) + return r; + + r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v); + if (r < 0) + return r; + + sd_dhcp_option_ref(v); + return 0; +} + int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); @@ -546,6 +575,14 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { return 0; } +int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) { + assert_return(client, -EINVAL); + + client->ip_service_type = type; + + return 0; +} + static int client_notify(sd_dhcp_client *client, int event) { assert(client); @@ -778,7 +815,7 @@ static int dhcp_client_send_raw( size_t len) { dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port, - INADDR_BROADCAST, DHCP_PORT_SERVER, len); + INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type); return dhcp_network_send_raw_socket(client->fd, &client->link, packet, len); @@ -787,6 +824,8 @@ static int dhcp_client_send_raw( static int client_send_discover(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *discover = NULL; size_t optoffset, optlen; + sd_dhcp_option *j; + Iterator i; int r; assert(client); @@ -803,7 +842,9 @@ static int client_send_discover(sd_dhcp_client *client) { address be assigned, and may include the ’IP address lease time’ option to suggest the lease time it would like. */ - if (client->last_addr != INADDR_ANY) { + /* RFC7844 section 3: + SHOULD NOT contain any other option. */ + if (!client->anonymize && client->last_addr != INADDR_ANY) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->last_addr); @@ -848,6 +889,13 @@ static int client_send_discover(sd_dhcp_client *client) { return r; } + ORDERED_HASHMAP_FOREACH(j, client->options, i) { + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + j->option, j->length, j->data); + if (r < 0) + return r; + } + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) @@ -866,41 +914,6 @@ static int client_send_discover(sd_dhcp_client *client) { return 0; } -static int client_send_release(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; - int r; - - assert(client); - assert(!IN_SET(client->state, DHCP_STATE_STOPPED)); - - r = client_message_init(client, &release, DHCP_RELEASE, - &optlen, &optoffset); - if (r < 0) - return r; - - /* Fill up release IP and MAC */ - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); - - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "RELEASE"); - - return 0; -} - static int client_send_request(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *request = NULL; size_t optoffset, optlen; @@ -1666,7 +1679,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i goto error; } - r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port); + r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type); if (r < 0) { log_dhcp_client(client, "could not bind UDP socket"); goto error; @@ -1925,8 +1938,35 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { int sd_dhcp_client_send_release(sd_dhcp_client *client) { assert_return(client, -EINVAL); + assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); + assert_return(client->lease, -EUNATCH); - client_send_release(client); + _cleanup_free_ DHCPPacket *release = NULL; + size_t optoffset, optlen; + int r; + + r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset); + if (r < 0) + return r; + + /* Fill up release IP and MAC */ + release->dhcp.ciaddr = client->lease->address; + memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); + + r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + r = dhcp_network_send_udp_socket(client->fd, + client->lease->server_address, + DHCP_PORT_SERVER, + &release->dhcp, + sizeof(DHCPMessage) + optoffset); + if (r < 0) + return r; + + log_dhcp_client(client, "RELEASE"); return 0; } @@ -1976,7 +2016,8 @@ sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { } static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { - assert(client); + if (!client) + return NULL; log_dhcp_client(client, "FREE"); @@ -1995,17 +2036,16 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { free(client->hostname); free(client->vendor_class_identifier); client->user_class = strv_free(client->user_class); + ordered_hashmap_free(client->options); return mfree(client); } DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free); int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { - _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL; - assert_return(ret, -EINVAL); - client = new(sd_dhcp_client, 1); + _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1); if (!client) return -ENOMEM; @@ -2018,6 +2058,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { .port = DHCP_PORT_CLIENT, .anonymize = !!anonymize, .max_attempts = (uint64_t) -1, + .ip_service_type = -1, }; /* NOTE: this could be moved to a function. */ if (anonymize) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index 3bf9c02064..ac6fe3f4d3 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -7,9 +7,7 @@ #include #include -#include #include -#include #include #include #include diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index f5b5ce6b94..e1150f9806 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -6,7 +6,6 @@ #include "nm-sd-adapt-core.h" #include -#include #include #include #include @@ -48,6 +47,7 @@ struct sd_dhcp6_client { sd_event *event; int event_priority; int ifindex; + DHCP6Address hint_pd_prefix; struct in6_addr local_address; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; @@ -189,6 +189,22 @@ int sd_dhcp6_client_set_mac( return 0; } +int sd_dhcp6_client_set_prefix_delegation_hint( + sd_dhcp6_client *client, + uint8_t prefixlen, + const struct in6_addr *pd_address) { + + assert_return(client, -EINVAL); + assert_return(pd_address, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->hint_pd_prefix.iapdprefix.address = *pd_address; + client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen; + + return 0; +} + static int client_ensure_duid(sd_dhcp6_client *client) { if (client->duid_len != 0) return 0; @@ -218,7 +234,7 @@ static int dhcp6_client_set_duid_internal( if (r < 0) { r = dhcp_validate_duid_len(duid_type, duid_len, false); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m"); log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type); } @@ -230,32 +246,32 @@ static int dhcp6_client_set_duid_internal( switch (duid_type) { case DUID_TYPE_LLT: if (client->mac_addr_len == 0) - return -EOPNOTSUPP; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set."); r = dhcp_identifier_set_duid_llt(&client->duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m"); break; case DUID_TYPE_EN: r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m"); break; case DUID_TYPE_LL: if (client->mac_addr_len == 0) - return -EOPNOTSUPP; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set."); r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m"); break; case DUID_TYPE_UUID: r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m"); break; default: - return -EINVAL; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type"); } #else /* NM_IGNORED */ g_return_val_if_reached (-EINVAL); @@ -498,7 +514,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd); + r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix); if (r < 0) return r; @@ -536,7 +552,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); + r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) return r; @@ -562,7 +578,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); + r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) return r; @@ -1543,6 +1559,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { .request = DHCP6_REQUEST_IA_NA, .fd = -1, .req_opts_len = ELEMENTSOF(default_req_opts), + .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1, + .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1, .req_opts = TAKE_PTR(req_opts), }; diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index e75614803d..3efa8170b1 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "sd-ipv4acd.h" diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index daac8839e2..2d17b4fe81 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -9,7 +9,6 @@ #include #include #include -#include #include "sd-id128.h" #include "sd-ipv4acd.h" diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index c37817062d..7c4566e342 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -18,7 +18,7 @@ #include "list.h" #include "macro.h" #include "memory-util.h" -#include "missing.h" +#include "missing_syscall.h" #include "prioq.h" #include "process-util.h" #include "set.h" @@ -773,11 +773,13 @@ static void source_disconnect(sd_event_source *s) { event = s->event; - s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID; s->event = NULL; LIST_REMOVE(sources, event->sources, s); event->n_sources--; + /* Note that we don't invalidate the type here, since we still need it in order to close the fd or + * pidfd associated with this event source, which we'll do only on source_free(). */ + if (!s->floating) sd_event_unref(event); } @@ -2556,7 +2558,7 @@ static int process_child(sd_event *e) { * benefit in leaving it queued */ assert(s->child.options & (WSTOPPED|WCONTINUED)); - waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); + (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); } r = source_set_pending(s, true); diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index eeb29e97d5..c0d0fe8188 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -15,7 +15,7 @@ #include "io-util.h" #include "khash.h" #include "macro.h" -#include "missing.h" +#include "missing_syscall.h" #include "random-util.h" #include "user-util.h" #include "util.h" diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index d2d74b2b4c..f97e35b654 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -26,6 +26,7 @@ #include #include "sd-dhcp-lease.h" +#include "sd-dhcp-option.h" #include "sd-event.h" #include "_sd-common.h" @@ -174,6 +175,11 @@ int sd_dhcp_client_set_user_class( int sd_dhcp_client_get_lease( sd_dhcp_client *client, sd_dhcp_lease **ret); +int sd_dhcp_client_set_service_type( + sd_dhcp_client *client, + int type); + +int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v); int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client); diff --git a/src/systemd/src/systemd/sd-dhcp-option.h b/src/systemd/src/systemd/sd-dhcp-option.h new file mode 100644 index 0000000000..45dbd27985 --- /dev/null +++ b/src/systemd/src/systemd/sd-dhcp-option.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#ifndef foosddhcpoptionhfoo +#define foosddhcpoptionhfoo + +/*** + Copyright © 2013 Intel Corporation. All rights reserved. + 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 . +***/ + +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_dhcp_option sd_dhcp_option; + +int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret); +sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra); +sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index 3aac3f14fe..be34d43e74 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -120,6 +120,10 @@ int sd_dhcp6_client_get_information_request( int sd_dhcp6_client_set_request_option( sd_dhcp6_client *client, uint16_t option); +int sd_dhcp6_client_set_prefix_delegation_hint( + sd_dhcp6_client *client, + uint8_t prefixlen, + const struct in6_addr *pd_address); int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation); int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,