diff options
author | Thomas Haller <thaller@redhat.com> | 2018-06-15 15:38:52 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-06-15 15:56:04 +0200 |
commit | 13f860970af1adfa58eb5d3b408a6bdfccf4e4d7 (patch) | |
tree | aeda946c635abab5815d548149971c9c11802da2 | |
parent | 046f7599829ddc8b77e79071c05e4f4d10c72052 (diff) | |
parent | 353810ccc15b85b4e013fcc6903913c02aca1a0c (diff) | |
download | NetworkManager-13f860970af1adfa58eb5d3b408a6bdfccf4e4d7.tar.gz |
systemd: merge branch systemd into master
112 files changed, 1915 insertions, 822 deletions
diff --git a/Makefile.am b/Makefile.am index f7bc85aeff..bd8194eb70 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1303,6 +1303,7 @@ src_libsystemd_nm_la_SOURCES = \ src/systemd/sd-adapt/cgroup-util.h \ src/systemd/sd-adapt/condition.h \ src/systemd/sd-adapt/conf-parser.h \ + src/systemd/sd-adapt/copy.h \ src/systemd/sd-adapt/def.h \ src/systemd/sd-adapt/device-nodes.h \ src/systemd/sd-adapt/dirent-util.h \ diff --git a/shared/nm-utils/unaligned.h b/shared/nm-utils/unaligned.h index feddaa9192..965a5fe99c 100644 --- a/shared/nm-utils/unaligned.h +++ b/shared/nm-utils/unaligned.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen + Copyright © 2014 Tom Gundersen ***/ #include <endian.h> diff --git a/src/systemd/sd-adapt/copy.h b/src/systemd/sd-adapt/copy.h new file mode 100644 index 0000000000..637892c2d6 --- /dev/null +++ b/src/systemd/sd-adapt/copy.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/src/systemd/src/basic/alloc-util.c b/src/systemd/src/basic/alloc-util.c index 79b823de42..ef40509833 100644 --- a/src/systemd/src/basic/alloc-util.c +++ b/src/systemd/src/basic/alloc-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h index bae6a28451..ebe42889ea 100644 --- a/src/systemd/src/basic/alloc-util.h +++ b/src/systemd/src/basic/alloc-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <alloca.h> #include <stddef.h> #include <stdlib.h> diff --git a/src/systemd/src/basic/async.h b/src/systemd/src/basic/async.h index 36f333778c..3160613184 100644 --- a/src/systemd/src/basic/async.h +++ b/src/systemd/src/basic/async.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering -***/ - int asynchronous_job(void* (*func)(void *p), void *arg); int asynchronous_sync(pid_t *ret_pid); diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c index f51de788f7..5c82a545fc 100644 --- a/src/systemd/src/basic/escape.c +++ b/src/systemd/src/basic/escape.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -17,8 +12,10 @@ #include "macro.h" #include "utf8.h" -size_t cescape_char(char c, char *buf) { - char * buf_old = buf; +int cescape_char(char c, char *buf) { + char *buf_old = buf; + + /* Needs space for 4 characters in the buffer */ switch (c) { diff --git a/src/systemd/src/basic/escape.h b/src/systemd/src/basic/escape.h index 80b0946e2a..c612a7c02d 100644 --- a/src/systemd/src/basic/escape.h +++ b/src/systemd/src/basic/escape.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <inttypes.h> #include <stddef.h> #include <stdint.h> @@ -47,7 +41,7 @@ typedef enum EscapeStyle { char *cescape(const char *s); char *cescape_length(const char *s, size_t n); -size_t cescape_char(char c, char *buf); +int cescape_char(char c, char *buf); int cunescape(const char *s, UnescapeFlags flags, char **ret); int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); diff --git a/src/systemd/src/basic/ether-addr-util.c b/src/systemd/src/basic/ether-addr-util.c index 75de9a1902..6f946c3e92 100644 --- a/src/systemd/src/basic/ether-addr-util.c +++ b/src/systemd/src/basic/ether-addr-util.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen + Copyright © 2014 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/ether-addr-util.h b/src/systemd/src/basic/ether-addr-util.h index f7e0de54cc..f02cefead3 100644 --- a/src/systemd/src/basic/ether-addr-util.h +++ b/src/systemd/src/basic/ether-addr-util.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen + Copyright © 2014 Tom Gundersen ***/ #include <net/ethernet.h> diff --git a/src/systemd/src/basic/extract-word.c b/src/systemd/src/basic/extract-word.c index 2adb8966ea..404fe61558 100644 --- a/src/systemd/src/basic/extract-word.c +++ b/src/systemd/src/basic/extract-word.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/extract-word.h b/src/systemd/src/basic/extract-word.h index d2113948f7..8c63b7c306 100644 --- a/src/systemd/src/basic/extract-word.h +++ b/src/systemd/src/basic/extract-word.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include "macro.h" typedef enum ExtractFlags { diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index 6a753195df..71babe2f2b 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -14,10 +9,13 @@ #include <sys/stat.h> #include <unistd.h> +#include "alloc-util.h" +#include "copy.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "io-util.h" #include "macro.h" #include "memfd-util.h" #include "missing.h" @@ -566,6 +564,201 @@ try_dev_shm_without_o_tmpfile: return -EOPNOTSUPP; } + +/* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */ +#define DATA_FD_MEMORY_LIMIT (64U*1024U) + +/* If memfd/pipe didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp instead. */ +#define DATA_FD_TMP_LIMIT (1024U*1024U) + +int fd_duplicate_data_fd(int fd) { + + _cleanup_close_ int copy_fd = -1, tmp_fd = -1; + _cleanup_free_ void *remains = NULL; + size_t remains_size = 0; + const char *td; + struct stat st; + int r; + + /* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only fashion, but + * independent of it (i.e. the source fd can be closed and unmounted after this call succeeded). Tries to be + * somewhat smart about where to place the data. In the best case uses a memfd(). If memfd() are not supported + * uses a pipe instead. For larger data will use an unlinked file in /tmp, and for even larger data one in + * /var/tmp. */ + + if (fstat(fd, &st) < 0) + return -errno; + + /* For now, let's only accept regular files, sockets, pipes and char devices */ + if (S_ISDIR(st.st_mode)) + return -EISDIR; + if (S_ISLNK(st.st_mode)) + return -ELOOP; + if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode)) + return -EBADFD; + + /* If we have reason to believe the data is bounded in size, then let's use memfds or pipes as backing fd. Note + * that we use the reported regular file size only as a hint, given that there are plenty special files in + * /proc and /sys which report a zero file size but can be read from. */ + + if (!S_ISREG(st.st_mode) || st.st_size < DATA_FD_MEMORY_LIMIT) { + + /* Try a memfd first */ + copy_fd = memfd_new("data-fd"); + if (copy_fd >= 0) { + off_t f; + + r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, 0); + if (r < 0) + return r; + + f = lseek(copy_fd, 0, SEEK_SET); + if (f != 0) + return -errno; + + if (r == 0) { + /* Did it fit into the limit? If so, we are done. */ + r = memfd_set_sealed(copy_fd); + if (r < 0) + return r; + + return TAKE_FD(copy_fd); + } + + /* Hmm, pity, this didn't fit. Let's fall back to /tmp then, see below */ + + } else { + _cleanup_(close_pairp) int pipefds[2] = { -1, -1 }; + int isz; + + /* If memfds aren't available, use a pipe. Set O_NONBLOCK so that we will get EAGAIN rather + * then block indefinitely when we hit the pipe size limit */ + + if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0) + return -errno; + + isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); + if (isz < 0) + return -errno; + + /* Try to enlarge the pipe size if necessary */ + if ((size_t) isz < DATA_FD_MEMORY_LIMIT) { + + (void) fcntl(pipefds[1], F_SETPIPE_SZ, DATA_FD_MEMORY_LIMIT); + + isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); + if (isz < 0) + return -errno; + } + + if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) { + + r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size); + if (r < 0 && r != -EAGAIN) + return r; /* If we get EAGAIN it could be because of the source or because of + * the destination fd, we can't know, as sendfile() and friends won't + * tell us. Hence, treat this as reason to fall back, just to be + * sure. */ + if (r == 0) { + /* Everything fit in, yay! */ + (void) fd_nonblock(pipefds[0], false); + + return TAKE_FD(pipefds[0]); + } + + /* Things didn't fit in. But we read data into the pipe, let's remember that, so that + * when writing the new file we incorporate this first. */ + copy_fd = TAKE_FD(pipefds[0]); + } + } + } + + /* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */ + if ((!S_ISREG(st.st_mode) || st.st_size < DATA_FD_TMP_LIMIT) && + (DATA_FD_MEMORY_LIMIT + remains_size) < DATA_FD_TMP_LIMIT) { + off_t f; + + tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC); + if (tmp_fd < 0) + return tmp_fd; + + if (copy_fd >= 0) { + /* If we tried a memfd/pipe first and it ended up being too large, then copy this into the + * temporary file first. */ + + r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, 0); + if (r < 0) + return r; + + assert(r == 0); + } + + if (remains_size > 0) { + /* If there were remaining bytes (i.e. read into memory, but not written out yet) from the + * failed copy operation, let's flush them out next. */ + + r = loop_write(tmp_fd, remains, remains_size, false); + if (r < 0) + return r; + } + + r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT - remains_size, COPY_REFLINK); + if (r < 0) + return r; + if (r == 0) + goto finish; /* Yay, it fit in */ + + /* It didn't fit in. Let's not forget to use what we already used */ + f = lseek(tmp_fd, 0, SEEK_SET); + if (f != 0) + return -errno; + + safe_close(copy_fd); + copy_fd = TAKE_FD(tmp_fd); + + remains = mfree(remains); + remains_size = 0; + } + + /* As last fallback use /var/tmp */ + r = var_tmp_dir(&td); + if (r < 0) + return r; + + tmp_fd = open_tmpfile_unlinkable(td, O_RDWR|O_CLOEXEC); + if (tmp_fd < 0) + return tmp_fd; + + if (copy_fd >= 0) { + /* If we tried a memfd/pipe first, or a file in /tmp, and it ended up being too large, than copy this + * into the temporary file first. */ + r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + if (r < 0) + return r; + + assert(r == 0); + } + + if (remains_size > 0) { + /* Then, copy in any read but not yet written bytes. */ + r = loop_write(tmp_fd, remains, remains_size, false); + if (r < 0) + return r; + } + + /* Copy in the rest */ + r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + if (r < 0) + return r; + + assert(r == 0); + +finish: + /* Now convert the O_RDWR file descriptor into an O_RDONLY one (and as side effect seek to the beginning of the + * file again */ + + return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC); +} #endif /* NM_IGNORED */ int fd_move_above_stdio(int fd) { @@ -739,4 +932,28 @@ int fd_reopen(int fd, int flags) { return new_fd; } + +int read_nr_open(void) { + _cleanup_free_ char *nr_open = NULL; + int r; + + /* Returns the kernel's current fd limit, either by reading it of /proc/sys if that works, or using the + * hard-coded default compiled-in value of current kernels (1M) if not. This call will never fail. */ + + r = read_one_line_file("/proc/sys/fs/nr_open", &nr_open); + if (r < 0) + log_debug_errno(r, "Failed to read /proc/sys/fs/nr_open, ignoring: %m"); + else { + int v; + + r = safe_atoi(nr_open, &v); + if (r < 0) + log_debug_errno(r, "Failed to parse /proc/sys/fs/nr_open value '%s', ignoring: %m", nr_open); + else + return v; + } + + /* If we fail, fallback to the hard-coded kernel limit of 1024 * 1024. */ + return 1024 * 1024; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index 89c3f34c7b..8adc959da8 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <dirent.h> #include <stdbool.h> #include <stdio.h> @@ -81,6 +75,8 @@ enum { int acquire_data_fd(const void *data, size_t size, unsigned flags); +int fd_duplicate_data_fd(int fd); + /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) @@ -106,3 +102,5 @@ static inline int make_null_stdio(void) { }) int fd_reopen(int fd, int flags); + +int read_nr_open(void); diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index 4f71384e39..2d3aef2c0c 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -209,6 +204,25 @@ fail: return 0; } +int write_string_filef( + const char *fn, + WriteStringFileFlags flags, + const char *format, ...) { + + _cleanup_free_ char *p = NULL; + va_list ap; + int r; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0) + return -ENOMEM; + + return write_string_file(fn, p, flags); +} + int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; int r; @@ -267,29 +281,35 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { #endif /* NM_IGNORED */ int read_full_stream(FILE *f, char **contents, size_t *size) { - size_t n, l; _cleanup_free_ char *buf = NULL; struct stat st; + size_t n, l; + int fd; assert(f); assert(contents); - if (fstat(fileno(f), &st) < 0) - return -errno; - n = LINE_MAX; - if (S_ISREG(st.st_mode)) { + fd = fileno(f); + if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's + * optimize our buffering) */ - /* Safety check */ - if (st.st_size > READ_FULL_BYTES_MAX) - return -E2BIG; + if (fstat(fileno(f), &st) < 0) + return -errno; + + if (S_ISREG(st.st_mode)) { + + /* Safety check */ + 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. */ - if (st.st_size > 0) - n = st.st_size + 1; + /* 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. */ + if (st.st_size > 0) + n = st.st_size + 1; + } } l = 0; @@ -680,21 +700,41 @@ static int parse_env_file_push( return 0; } -int parse_env_file( +int parse_env_filev( + FILE *f, const char *fname, - const char *newline, ...) { + const char *newline, + va_list ap) { - va_list ap; int r, n_pushed = 0; + va_list aq; if (!newline) newline = NEWLINE; + va_copy(aq, ap); + r = parse_env_file_internal(f, fname, newline, parse_env_file_push, &aq, &n_pushed); + va_end(aq); + if (r < 0) + return r; + + return n_pushed; +} + +int parse_env_file( + FILE *f, + const char *fname, + const char *newline, + ...) { + + va_list ap; + int r; + va_start(ap, newline); - r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed); + r = parse_env_filev(f, fname, newline, ap); va_end(ap); - return r < 0 ? r : n_pushed; + return r; } #if 0 /* NM_IGNORED */ @@ -1218,7 +1258,7 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); - *ret = path_kill_slashes(t); + *ret = path_simplify(t, false); return 0; } @@ -1260,7 +1300,7 @@ int tempfn_random(const char *p, const char *extra, char **ret) { *x = 0; - *ret = path_kill_slashes(t); + *ret = path_simplify(t, false); return 0; } @@ -1300,7 +1340,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { *x = 0; - *ret = path_kill_slashes(t); + *ret = path_simplify(t, false); return 0; } @@ -1528,21 +1568,29 @@ int read_nul_string(FILE *f, char **ret) { } int mkdtemp_malloc(const char *template, char **ret) { - char *p; + _cleanup_free_ char *p = NULL; + int r; - assert(template); assert(ret); - p = strdup(template); + if (template) + p = strdup(template); + else { + const char *tmp; + + r = tmp_dir(&tmp); + if (r < 0) + return r; + + p = strjoin(tmp, "/XXXXXX"); + } if (!p) return -ENOMEM; - if (!mkdtemp(p)) { - free(p); + if (!mkdtemp(p)) return -errno; - } - *ret = p; + *ret = TAKE_PTR(p); return 0; } diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h index bed7c8fb7e..77e6206e95 100644 --- a/src/systemd/src/basic/fileio.h +++ b/src/systemd/src/basic/fileio.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <dirent.h> #include <stdbool.h> #include <stddef.h> @@ -17,12 +11,12 @@ #include "time-util.h" typedef enum { - WRITE_STRING_FILE_CREATE = 1<<0, - WRITE_STRING_FILE_ATOMIC = 1<<1, - WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2, - WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3, - WRITE_STRING_FILE_SYNC = 1<<4, - WRITE_STRING_FILE_DISABLE_BUFFER = 1<<5, + WRITE_STRING_FILE_CREATE = 1 << 0, + WRITE_STRING_FILE_ATOMIC = 1 << 1, + WRITE_STRING_FILE_AVOID_NEWLINE = 1 << 2, + WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3, + WRITE_STRING_FILE_SYNC = 1 << 4, + WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5, /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file() @@ -39,13 +33,16 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin return write_string_file_ts(fn, line, flags, NULL); } +int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4); + int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); int verify_file(const char *fn, const char *blob, bool accept_extra_nl); -int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; +int parse_env_filev(FILE *f, const char *fname, const char *separator, va_list ap); +int parse_env_file(FILE *f, const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index 049b238e8d..e3ae991605 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -234,6 +229,22 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { return 0; } + +int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (fchmod(fd, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (fchown(fd, uid, gid) < 0) + return -errno; + + return 0; +} #endif /* NM_IGNORED */ int fchmod_umask(int fd, mode_t m) { @@ -249,7 +260,7 @@ int fchmod_umask(int fd, mode_t m) { #if 0 /* NM_IGNORED */ int fchmod_opath(int fd, mode_t m) { - char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; /* This function operates also on fd that might have been opened with * O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like @@ -571,6 +582,7 @@ int unlink_or_warn(const char *filename) { return 0; } +#endif /* NM_IGNORED */ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; @@ -586,6 +598,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { return r; } +#if 0 /* NM_IGNORED */ static bool safe_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 @@ -609,10 +622,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 & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN)) + if (FLAGS_SET(flags, CHASE_NONEXISTENT | CHASE_OPEN)) return -EINVAL; - if ((flags & (CHASE_STEP|CHASE_OPEN)) == (CHASE_STEP|CHASE_OPEN)) + if (FLAGS_SET(flags, CHASE_STEP | CHASE_OPEN)) return -EINVAL; if (isempty(path)) @@ -1073,6 +1086,15 @@ int access_fd(int fd, int mode) { return r; } +void unlink_tempfilep(char (*p)[]) { + /* If the file is created with mkstemp(), it will (almost always) + * change the suffix. Treat this as a sign that the file was + * successfully created. We ignore both the rare case where the + * original suffix is used and unlink failures. */ + if (!endswith(*p, ".XXXXXX")) + (void) unlink_noerrno(*p); +} + int unlinkat_deallocate(int fd, const char *name, int flags) { _cleanup_close_ int truncate_fd = -1; struct stat st; @@ -1153,9 +1175,9 @@ int fsync_directory_of_file(int fd) { r = fd_get_path(fd, &path); if (r < 0) { - log_debug("Failed to query /proc/self/fd/%d%s: %m", - fd, - r == -EOPNOTSUPP ? ", ignoring" : ""); + log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m", + fd, + r == -EOPNOTSUPP ? ", ignoring" : ""); if (r == -EOPNOTSUPP) /* If /proc is not available, we're most likely running in some diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 6157fe81bf..28566773c6 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <dirent.h> #include <fcntl.h> #include <limits.h> @@ -31,6 +25,7 @@ int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid); int fchmod_umask(int fd, mode_t mode); int fchmod_opath(int fd, mode_t m); @@ -70,13 +65,13 @@ union inotify_event_buffer { int inotify_add_watch_fd(int fd, int what, uint32_t mask); enum { - CHASE_PREFIX_ROOT = 1U << 0, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ - CHASE_NONEXISTENT = 1U << 1, /* If set, it's OK if the path doesn't actually exist. */ - CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */ - CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ - CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */ - CHASE_TRAIL_SLASH = 1U << 5, /* If set, any trailing slash will be preserved */ - CHASE_STEP = 1U << 6, /* If set, just execute a single step of the normalization */ + CHASE_PREFIX_ROOT = 1 << 0, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ + CHASE_NONEXISTENT = 1 << 1, /* If set, it's OK if the path doesn't actually exist. */ + CHASE_NO_AUTOFS = 1 << 2, /* If set, return -EREMOTE if autofs mount point found */ + CHASE_SAFE = 1 << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ + CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */ + CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */ + CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */ }; /* How many iterations to execute before returning -ELOOP */ @@ -104,6 +99,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); int access_fd(int fd, int mode); +void unlink_tempfilep(char (*p)[]); int unlinkat_deallocate(int fd, const char *name, int flags); int fsync_directory_of_file(int fd); diff --git a/src/systemd/src/basic/hash-funcs.c b/src/systemd/src/basic/hash-funcs.c index cb763f56fb..7ed35cb165 100644 --- a/src/systemd/src/basic/hash-funcs.c +++ b/src/systemd/src/basic/hash-funcs.c @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2014 Michal Schmidt + Copyright © 2014 Michal Schmidt ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/hash-funcs.h b/src/systemd/src/basic/hash-funcs.h index 0c963af8ef..3715c56e07 100644 --- a/src/systemd/src/basic/hash-funcs.h +++ b/src/systemd/src/basic/hash-funcs.h @@ -2,10 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2014 Michal Schmidt + Copyright © 2014 Michal Schmidt ***/ #include "macro.h" diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c index b8a8e37b5c..c91f8bd23a 100644 --- a/src/systemd/src/basic/hashmap.c +++ b/src/systemd/src/basic/hashmap.c @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2014 Michal Schmidt + Copyright © 2014 Michal Schmidt ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/hashmap.h b/src/systemd/src/basic/hashmap.h index 701eecbdb0..d1d1b9c8a4 100644 --- a/src/systemd/src/basic/hashmap.h +++ b/src/systemd/src/basic/hashmap.h @@ -2,10 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2014 Michal Schmidt + Copyright © 2014 Michal Schmidt ***/ #include <limits.h> diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c index 1fe410f56a..09f2a9e711 100644 --- a/src/systemd/src/basic/hexdecoct.c +++ b/src/systemd/src/basic/hexdecoct.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/hexdecoct.h b/src/systemd/src/basic/hexdecoct.h index c2f11013e5..9477d16e37 100644 --- a/src/systemd/src/basic/hexdecoct.h +++ b/src/systemd/src/basic/hexdecoct.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <stdbool.h> #include <stddef.h> #include <stdio.h> diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c index 0feeaa5d31..85708394b7 100644 --- a/src/systemd/src/basic/hostname-util.c +++ b/src/systemd/src/basic/hostname-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2015 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h index 8e29e9e1e5..749481723d 100644 --- a/src/systemd/src/basic/hostname-util.h +++ b/src/systemd/src/basic/hostname-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2015 Lennart Poettering -***/ - #include <stdbool.h> #include <stdio.h> diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c index 65748615b0..d945567aee 100644 --- a/src/systemd/src/basic/in-addr-util.c +++ b/src/systemd/src/basic/in-addr-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h index acd567c994..956c00a850 100644 --- a/src/systemd/src/basic/in-addr-util.h +++ b/src/systemd/src/basic/in-addr-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering -***/ - #include <netinet/in.h> #include <stddef.h> #include <sys/socket.h> diff --git a/src/systemd/src/basic/io-util.c b/src/systemd/src/basic/io-util.c index 1bc5c34599..6f46c944ea 100644 --- a/src/systemd/src/basic/io-util.c +++ b/src/systemd/src/basic/io-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/io-util.h b/src/systemd/src/basic/io-util.h index e4717b6f30..ed189b5820 100644 --- a/src/systemd/src/basic/io-util.h +++ b/src/systemd/src/basic/io-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <stdbool.h> #include <stddef.h> #include <stdint.h> diff --git a/src/systemd/src/basic/list.h b/src/systemd/src/basic/list.h index 3ec7e73fc5..643e0bea88 100644 --- a/src/systemd/src/basic/list.h +++ b/src/systemd/src/basic/list.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - /* The head of the linked list. Use this in the structure that shall * contain the head of the linked list */ #define LIST_HEAD(t,name) \ diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h index e7d7c8b14d..28edd57255 100644 --- a/src/systemd/src/basic/log.h +++ b/src/systemd/src/basic/log.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <stdarg.h> #include <stdbool.h> #include <stdlib.h> @@ -251,7 +245,7 @@ int log_emergency_level(void); /* Structured logging */ #define log_struct_errno(level, error, ...) \ log_struct_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \ - error, __FILE__, __LINE__, __func__, __VA_ARGS__) + error, __FILE__, __LINE__, __func__, __VA_ARGS__, NULL) #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ @@ -290,6 +284,8 @@ void log_set_open_when_needed(bool b); * stderr, the console or kmsg */ void log_set_prohibit_ipc(bool b); +int log_dup_console(void); + int log_syntax_internal( const char *unit, int level, diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index c89fb84ed5..cdb54f82ac 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <inttypes.h> #include <stdbool.h> #include <sys/param.h> @@ -366,6 +360,8 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) +#define FLAGS_SET(v, flags) \ + (((v) & (flags)) == (flags)) #define CASE_F(X) case X: #define CASE_F_1(CASE, X) CASE_F(X) diff --git a/src/systemd/src/basic/mempool.c b/src/systemd/src/basic/mempool.c index 0709676696..a0154263f2 100644 --- a/src/systemd/src/basic/mempool.c +++ b/src/systemd/src/basic/mempool.c @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2010-2014 Lennart Poettering - Copyright 2014 Michal Schmidt + Copyright © 2014 Michal Schmidt ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/mempool.h b/src/systemd/src/basic/mempool.h index 68249cd881..291415deb0 100644 --- a/src/systemd/src/basic/mempool.h +++ b/src/systemd/src/basic/mempool.h @@ -2,10 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2011-2014 Lennart Poettering - Copyright 2014 Michal Schmidt + Copyright © 2014 Michal Schmidt ***/ #include <stddef.h> @@ -29,7 +26,6 @@ static struct mempool pool_name = { \ .at_least = alloc_at_least, \ } - #if VALGRIND void mempool_drop(struct mempool *mp); #endif diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index ae43a0411b..7d6bcb5a45 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -637,6 +632,58 @@ int parse_percent(const char *p) { return v; } +int parse_permille_unbounded(const char *p) { + const char *pc, *pm, *dot, *n; + int r, q, v; + + pm = endswith(p, "‰"); + if (pm) { + n = strndupa(p, pm - p); + r = safe_atoi(n, &v); + if (r < 0) + return r; + } else { + pc = endswith(p, "%"); + if (!pc) + return -EINVAL; + + dot = memchr(p, '.', pc - p); + if (dot) { + if (dot + 2 != pc) + return -EINVAL; + if (dot[1] < '0' || dot[1] > '9') + return -EINVAL; + q = dot[1] - '0'; + n = strndupa(p, dot - p); + } else { + q = 0; + n = strndupa(p, pc - p); + } + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v > (INT_MAX - q) / 10) + return -ERANGE; + + v = v * 10 + q; + } + + if (v < 0) + return -ERANGE; + + return v; +} + +int parse_permille(const char *p) { + int v; + + v = parse_permille_unbounded(p); + if (v > 1000) + return -ERANGE; + + return v; +} + int parse_nice(const char *p, int *ret) { int n, r; diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 2b75b938c7..f3267f4cfe 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <inttypes.h> #include <limits.h> #include <stddef.h> @@ -115,6 +109,9 @@ int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); int parse_percent_unbounded(const char *p); int parse_percent(const char *p); +int parse_permille_unbounded(const char *p); +int parse_permille(const char *p); + int parse_nice(const char *p, int *ret); int parse_ip_port(const char *s, uint16_t *ret); diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index 567fc61cea..69bdb894cf 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -34,12 +29,13 @@ #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "utf8.h" -#if 0 /* NM_IGNORED */ bool path_is_absolute(const char *p) { return p[0] == '/'; } +#if 0 /* NM_IGNORED */ bool is_path(const char *p) { return !!strchr(p, '/'); } @@ -130,8 +126,8 @@ int path_make_absolute_cwd(const char *p, char **ret) { } int path_make_relative(const char *from_dir, const char *to_path, char **_r) { - char *r, *p; - unsigned n_parents; + char *f, *t, *r, *p; + unsigned n_parents = 0; assert(from_dir); assert(to_path); @@ -139,85 +135,81 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) { /* Strips the common part, and adds ".." elements as necessary. */ - if (!path_is_absolute(from_dir)) + if (!path_is_absolute(from_dir) || !path_is_absolute(to_path)) return -EINVAL; - if (!path_is_absolute(to_path)) - return -EINVAL; + f = strdupa(from_dir); + t = strdupa(to_path); + + path_simplify(f, true); + path_simplify(t, true); /* Skip the common part. */ for (;;) { size_t a, b; - from_dir += strspn(from_dir, "/"); - to_path += strspn(to_path, "/"); + f += *f == '/'; + t += *t == '/'; - if (!*from_dir) { - if (!*to_path) + if (!*f) { + if (!*t) /* from_dir equals to_path. */ r = strdup("."); else /* from_dir is a parent directory of to_path. */ - r = strdup(to_path); + r = strdup(t); if (!r) return -ENOMEM; - path_kill_slashes(r); - *_r = r; return 0; } - if (!*to_path) + if (!*t) break; - a = strcspn(from_dir, "/"); - b = strcspn(to_path, "/"); + a = strcspn(f, "/"); + b = strcspn(t, "/"); - if (a != b) + if (a != b || memcmp(f, t, a) != 0) break; - if (memcmp(from_dir, to_path, a) != 0) - break; - - from_dir += a; - to_path += b; + f += a; + t += b; } /* If we're here, then "from_dir" has one or more elements that need to * be replaced with "..". */ /* Count the number of necessary ".." elements. */ - for (n_parents = 0;;) { + for (; *f;) { size_t w; - from_dir += strspn(from_dir, "/"); - - if (!*from_dir) - break; - - w = strcspn(from_dir, "/"); + w = strcspn(f, "/"); /* If this includes ".." we can't do a simple series of "..", refuse */ - if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.') + if (w == 2 && f[0] == '.' && f[1] == '.') return -EINVAL; - /* Count number of elements, except if they are "." */ - if (w != 1 || from_dir[0] != '.') - n_parents++; + /* Count number of elements */ + n_parents++; - from_dir += w; + f += w; + f += *f == '/'; } - r = new(char, n_parents * 3 + strlen(to_path) + 1); + r = new(char, n_parents * 3 + strlen(t) + 1); if (!r) return -ENOMEM; for (p = r; n_parents > 0; n_parents--) p = mempcpy(p, "../", 3); - strcpy(p, to_path); - path_kill_slashes(r); + if (*t) + strcpy(p, t); + else + /* Remove trailing slash */ + *(--p) = 0; *_r = r; return 0; @@ -238,7 +230,7 @@ int path_strv_make_absolute_cwd(char **l) { if (r < 0) return r; - path_kill_slashes(t); + path_simplify(t, false); free_and_replace(*s, t); } @@ -339,17 +331,30 @@ char **path_strv_resolve_uniq(char **l, const char *root) { } #endif /* NM_IGNORED */ -char *path_kill_slashes(char *path) { +char *path_simplify(char *path, bool kill_dots) { char *f, *t; - bool slash = false; + bool slash = false, ignore_slash = false, absolute; + + assert(path); - /* Removes redundant inner and trailing slashes. Modifies the - * passed string in-place. + /* Removes redundant inner and trailing slashes. Also removes unnecessary dots + * if kill_dots is true. Modifies the passed string in-place. * - * ///foo///bar/ becomes /foo/bar + * ///foo//./bar/. becomes /foo/./bar/. (if kill_dots is false) + * ///foo//./bar/. becomes /foo/bar (if kill_dots is true) + * .//./foo//./bar/. becomes ./foo/bar (if kill_dots is false) + * .//./foo//./bar/. becomes foo/bar (if kill_dots is true) */ - for (f = path, t = path; *f; f++) { + absolute = path_is_absolute(path); + + f = path; + if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) { + ignore_slash = true; + f++; + } + + for (t = path; *f; f++) { if (*f == '/') { slash = true; @@ -357,17 +362,21 @@ char *path_kill_slashes(char *path) { } if (slash) { + if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) + continue; + slash = false; - *(t++) = '/'; + if (ignore_slash) + ignore_slash = false; + else + *(t++) = '/'; } *(t++) = *f; } - /* Special rule, if we are talking of the root directory, a - trailing slash is good */ - - if (t == path && slash) + /* Special rule, if we are talking of the root directory, a trailing slash is good */ + if (absolute && t == path) *(t++) = '/'; *t = 0; @@ -535,7 +544,7 @@ int find_binary(const char *name, char **ret) { /* Found it! */ if (ret) { - *ret = path_kill_slashes(j); + *ret = path_simplify(j, false); j = NULL; } @@ -689,12 +698,11 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar if (r < 0) return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); - path_kill_slashes(p); + path_simplify(p, false); if (suppress_root && empty_or_root(p)) p = mfree(p); - free(*arg); - *arg = p; + free_and_replace(*arg, p); return 0; } @@ -778,7 +786,6 @@ bool filename_is_valid(const char *p) { return true; } -#if 0 /* NM_IGNORED */ bool path_is_normalized(const char *p) { if (isempty(p)) @@ -802,6 +809,7 @@ bool path_is_normalized(const char *p) { return true; } +#if 0 /* NM_IGNORED */ char *file_in_same_dir(const char *path, const char *filename) { char *e, *ret; size_t k; @@ -880,17 +888,36 @@ bool hidden_or_backup_file(const char *filename) { bool is_device_path(const char *path) { - /* Returns true on paths that refer to a device, either in - * sysfs or in /dev */ + /* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */ + + return PATH_STARTSWITH_SET(path, "/dev/", "/sys/"); +} + +bool valid_device_node_path(const char *path) { + + /* Some superficial checks whether the specified path is a valid device node path, all without looking at the + * actual device node. */ + + if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/")) + return false; + + if (endswith(path, "/")) /* can't be a device node if it ends in a slash */ + return false; - return path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); + return path_is_normalized(path); } -bool is_deviceallow_pattern(const char *path) { - return path_startswith(path, "/dev/") || - startswith(path, "block-") || - startswith(path, "char-"); +bool valid_device_allow_pattern(const char *path) { + assert(path); + + /* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny= + * accept it */ + + if (startswith(path, "block-") || + startswith(path, "char-")) + return true; + + return valid_device_node_path(path); } int systemd_installation_has_version(const char *root, unsigned minimal_version) { @@ -926,7 +953,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version) if (r < 0) return r; - assert_se((c = endswith(path, "*.so"))); + assert_se(c = endswith(path, "*.so")); *c = '\0'; /* truncate the glob part */ STRV_FOREACH(name, names) { @@ -975,6 +1002,7 @@ bool dot_or_dot_dot(const char *path) { return path[2] == 0; } +#if 0 /* NM_IGNORED */ bool empty_or_root(const char *root) { /* For operations relative to some root directory, returns true if the specified root directory is redundant, @@ -985,3 +1013,51 @@ bool empty_or_root(const char *root) { return root[strspn(root, "/")] == 0; } + +int path_simplify_and_warn( + char *path, + unsigned flag, + const char *unit, + const char *filename, + unsigned line, + const char *lvalue) { + + bool absolute, fatal = flag & PATH_CHECK_FATAL; + + assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)); + + if (!utf8_is_valid(path)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path); + return -EINVAL; + } + + if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) { + absolute = path_is_absolute(path); + + if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "%s= path is not absolute%s: %s", + lvalue, fatal ? "" : ", ignoring", path); + return -EINVAL; + } + + if (absolute && (flag & PATH_CHECK_RELATIVE)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "%s= path is absolute%s: %s", + lvalue, fatal ? "" : ", ignoring", path); + return -EINVAL; + } + } + + path_simplify(path, true); + + if (!path_is_normalized(path)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "%s= path is not normalized%s: %s", + lvalue, fatal ? "" : ", ignoring", path); + return -EINVAL; + } + + return 0; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index 79db819e4d..519060cf53 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering -***/ - #include <alloca.h> #include <stdbool.h> #include <stddef.h> @@ -52,12 +46,12 @@ char* path_make_absolute(const char *p, const char *prefix); int safe_getcwd(char **ret); int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from_dir, const char *to_path, char **_r); -char* path_kill_slashes(char *path); char* path_startswith(const char *path, const char *prefix) _pure_; int path_compare(const char *a, const char *b) _pure_; bool path_equal(const char *a, const char *b) _pure_; bool path_equal_or_files_same(const char *a, const char *b, int flags); char* path_join(const char *root, const char *path, const char *rest); +char* path_simplify(char *path, bool kill_dots); static inline bool path_equal_ptr(const char *a, const char *b) { return !!a == !!b && (!a || path_equal(a, b)); @@ -103,11 +97,11 @@ int mkfs_exists(const char *fstype); * the tree, to root. Also returns "" (and not "/"!) for the root * directory. Excludes the specified directory itself */ #define PATH_FOREACH_PREFIX(prefix, path) \ - for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ #define PATH_FOREACH_PREFIX_MORE(prefix, path) \ - for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) char *prefix_root(const char *root, const char *path); @@ -149,7 +143,9 @@ char *file_in_same_dir(const char *path, const char *filename); bool hidden_or_backup_file(const char *filename) _pure_; bool is_device_path(const char *path); -bool is_deviceallow_pattern(const char *path); + +bool valid_device_node_path(const char *path); +bool valid_device_allow_pattern(const char *path); int systemd_installation_has_version(const char *root, unsigned minimal_version); @@ -169,3 +165,11 @@ bool empty_or_root(const char *root); static inline const char *empty_to_root(const char *path) { return isempty(path) ? "/" : path; } + +enum { + PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */ + PATH_CHECK_ABSOLUTE = 1 << 1, + PATH_CHECK_RELATIVE = 1 << 2, +}; + +int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue); diff --git a/src/systemd/src/basic/prioq.c b/src/systemd/src/basic/prioq.c index 805a617458..79900df353 100644 --- a/src/systemd/src/basic/prioq.c +++ b/src/systemd/src/basic/prioq.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering -***/ /* * Priority Queue diff --git a/src/systemd/src/basic/prioq.h b/src/systemd/src/basic/prioq.h index e348c64649..e036175260 100644 --- a/src/systemd/src/basic/prioq.h +++ b/src/systemd/src/basic/prioq.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering -***/ - #include <stdbool.h> #include "hashmap.h" diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c index 4af99957d2..10aa0e56d5 100644 --- a/src/systemd/src/basic/process-util.c +++ b/src/systemd/src/basic/process-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -19,6 +14,7 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <sys/mount.h> #include <sys/personality.h> #include <sys/prctl.h> #include <sys/types.h> @@ -80,20 +76,31 @@ int get_process_state(pid_t pid) { return (unsigned char) state; } -int get_process_comm(pid_t pid, char **name) { +int get_process_comm(pid_t pid, char **ret) { + _cleanup_free_ char *escaped = NULL, *comm = NULL; const char *p; int r; - assert(name); + assert(ret); assert(pid >= 0); + escaped = new(char, TASK_COMM_LEN); + if (!escaped) + return -ENOMEM; + p = procfs_file_alloca(pid, "comm"); - r = read_one_line_file(p, name); + r = read_one_line_file(p, &comm); if (r == -ENOENT) return -ESRCH; + if (r < 0) + return r; - return r; + /* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */ + cellescape(escaped, TASK_COMM_LEN, comm); + + *ret = TAKE_PTR(escaped); + return 0; } int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { @@ -251,15 +258,10 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * memcpy(ans, "[...]", max_length-1); ans[max_length-1] = 0; } else { - char *e; - t[max_length - 6] = 0; /* Chop off final spaces */ - e = strchr(t, 0); - while (e > t && isspace(e[-1])) - e--; - *e = 0; + delete_trailing_chars(t, WHITESPACE); ans = strjoin("[", t, "...]"); } @@ -300,7 +302,7 @@ int rename_process(const char name[]) { * can use PR_SET_NAME, which sets the thread name for the calling thread. */ if (prctl(PR_SET_NAME, name) < 0) log_debug_errno(errno, "PR_SET_NAME failed: %m"); - if (l > 15) /* Linux process names can be 15 chars at max */ + if (l >= TASK_COMM_LEN) /* Linux process names can be 15 chars at max */ truncated = true; /* Second step, change glibc's ID of the process name. */ @@ -744,14 +746,17 @@ int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) { /* * Return values: - * < 0 : wait_for_terminate_with_timeout() failed to get the state of the - * process, the process timed out, the process was terminated by a - * signal, or failed for an unknown reason. + * + * < 0 : wait_for_terminate_with_timeout() failed to get the state of the process, the process timed out, the process + * was terminated by a signal, or failed for an unknown reason. + * * >=0 : The process terminated normally with no failures. * - * Success is indicated by a return value of zero, a timeout is indicated - * by ETIMEDOUT, and all other child failure states are indicated by error - * is indicated by a non-zero value. + * Success is indicated by a return value of zero, a timeout is indicated by ETIMEDOUT, and all other child failure + * states are indicated by error is indicated by a non-zero value. + * + * This call assumes SIGCHLD has been blocked already, in particular before the child to wait for has been forked off + * to remain entirely race-free. */ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) { sigset_t mask; @@ -1353,6 +1358,16 @@ int safe_fork_full( } } + if (FLAGS_SET(flags, FORK_NEW_MOUNTNS | FORK_MOUNTNS_SLAVE)) { + + /* Optionally, make sure we never propagate mounts to the host. */ + + if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { + log_full_errno(prio, errno, "Failed to remount root directory as MS_SLAVE: %m"); + _exit(EXIT_FAILURE); + } + } + if (flags & FORK_CLOSE_ALL_FDS) { /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */ log_close(); diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h index e3bf36bf04..e11164bd82 100644 --- a/src/systemd/src/basic/process-util.h +++ b/src/systemd/src/basic/process-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <alloca.h> #include <errno.h> #include <sched.h> @@ -51,8 +45,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid); int wait_for_terminate(pid_t pid, siginfo_t *status); typedef enum WaitFlags { - WAIT_LOG_ABNORMAL = 1U << 0, - WAIT_LOG_NON_ZERO_EXIT_STATUS = 1U << 1, + WAIT_LOG_ABNORMAL = 1 << 0, + WAIT_LOG_NON_ZERO_EXIT_STATUS = 1 << 1, /* A shortcut for requesting the most complete logging */ WAIT_LOG = WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS, @@ -157,14 +151,15 @@ void reset_cached_pid(void); int must_be_root(void); typedef enum ForkFlags { - FORK_RESET_SIGNALS = 1U << 0, - FORK_CLOSE_ALL_FDS = 1U << 1, - FORK_DEATHSIG = 1U << 2, - FORK_NULL_STDIO = 1U << 3, - FORK_REOPEN_LOG = 1U << 4, - FORK_LOG = 1U << 5, - FORK_WAIT = 1U << 6, - FORK_NEW_MOUNTNS = 1U << 7, + FORK_RESET_SIGNALS = 1 << 0, + FORK_CLOSE_ALL_FDS = 1 << 1, + FORK_DEATHSIG = 1 << 2, + FORK_NULL_STDIO = 1 << 3, + FORK_REOPEN_LOG = 1 << 4, + FORK_LOG = 1 << 5, + FORK_WAIT = 1 << 6, + FORK_NEW_MOUNTNS = 1 << 7, + FORK_MOUNTNS_SLAVE = 1 << 8, } ForkFlags; int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid); diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c index d80751cfe9..01a8488f88 100644 --- a/src/systemd/src/basic/random-util.c +++ b/src/systemd/src/basic/random-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -48,9 +43,9 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) { * for us. */ /* Use the getrandom() syscall unless we know we don't have it. */ - if (have_syscall != 0) { + if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) { #if !HAVE_GETRANDOM - /* XXX: NM: systemd calls the syscall directly in this case. Don't add that workaround. + /* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround. * If you don't compile against a libc that provides getrandom(), you don't get it. */ r = -1; errno = ENOSYS; diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h index 723917057d..9a103f0e94 100644 --- a/src/systemd/src/basic/random-util.h +++ b/src/systemd/src/basic/random-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <stdbool.h> #include <stddef.h> #include <stdint.h> diff --git a/src/systemd/src/basic/refcnt.h b/src/systemd/src/basic/refcnt.h index 0d5b3f4e1b..d2be6086d2 100644 --- a/src/systemd/src/basic/refcnt.h +++ b/src/systemd/src/basic/refcnt.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering -***/ - /* A type-safe atomic refcounter. * * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h index dc0f1e17e6..664713810d 100644 --- a/src/systemd/src/basic/set.h +++ b/src/systemd/src/basic/set.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include "extract-word.h" #include "hashmap.h" #include "macro.h" diff --git a/src/systemd/src/basic/signal-util.h b/src/systemd/src/basic/signal-util.h index 0c43467b63..92f2804cd2 100644 --- a/src/systemd/src/basic/signal-util.h +++ b/src/systemd/src/basic/signal-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2015 Lennart Poettering -***/ - #include <signal.h> #include "macro.h" diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index aa06070e6b..a71db5a7ea 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -793,7 +788,7 @@ static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIN DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *n) { +SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *n) { int r; r = parse_boolean(n); diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index c2d21b45c4..e2db795ae6 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <netinet/ether.h> #include <netinet/in.h> #include <stdbool.h> @@ -118,7 +112,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret); const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_; SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_; -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *s); +SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s); int netlink_family_to_string_alloc(int b, char **s); int netlink_family_from_string(const char *s) _pure_; diff --git a/src/systemd/src/basic/stat-util.c b/src/systemd/src/basic/stat-util.c index 28e75618bc..9892d8bc5c 100644 --- a/src/systemd/src/basic/stat-util.c +++ b/src/systemd/src/basic/stat-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -135,32 +130,6 @@ int path_is_read_only_fs(const char *path) { return false; } -int path_is_os_tree(const char *path) { - int r; - - assert(path); - - /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir - * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from - * the case where just the os-release file is missing. */ - if (laccess(path, F_OK) < 0) - return -errno; - - /* We use /usr/lib/os-release as flag file if something is an OS */ - r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL); - if (r == -ENOENT) { - - /* Also check for the old location in /etc, just in case. */ - r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL); - if (r == -ENOENT) - return 0; /* We got nothing */ - } - if (r < 0) - return r; - - return 1; -} - int files_same(const char *filea, const char *fileb, int flags) { struct stat a, b; diff --git a/src/systemd/src/basic/stat-util.h b/src/systemd/src/basic/stat-util.h index d1e8d33001..f8014ed30b 100644 --- a/src/systemd/src/basic/stat-util.h +++ b/src/systemd/src/basic/stat-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering -***/ - #include <stdbool.h> #include <stddef.h> #include <sys/stat.h> @@ -35,7 +29,6 @@ int null_or_empty_path(const char *fn); int null_or_empty_fd(int fd); int path_is_read_only_fs(const char *path); -int path_is_os_tree(const char *path); int files_same(const char *filea, const char *fileb, int flags); diff --git a/src/systemd/src/basic/stdio-util.h b/src/systemd/src/basic/stdio-util.h index 5330789aaa..73c03274c7 100644 --- a/src/systemd/src/basic/stdio-util.h +++ b/src/systemd/src/basic/stdio-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <printf.h> #include <stdarg.h> #include <stdio.h> diff --git a/src/systemd/src/basic/string-table.c b/src/systemd/src/basic/string-table.c index 34723b4c2e..94412ed2b4 100644 --- a/src/systemd/src/basic/string-table.c +++ b/src/systemd/src/basic/string-table.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/string-table.h b/src/systemd/src/basic/string-table.h index a39206fb94..9bd7879355 100644 --- a/src/systemd/src/basic/string-table.h +++ b/src/systemd/src/basic/string-table.h @@ -2,12 +2,6 @@ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <errno.h> #include <stddef.h> #include <stdio.h> @@ -77,7 +71,6 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) -1; \ } \ - #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) @@ -102,3 +95,18 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) + +#define DUMP_STRING_TABLE(name,type,max) \ + do { \ + type _k; \ + flockfile(stdout); \ + for (_k = 0; _k < (max); _k++) { \ + const char *_t; \ + _t = name##_to_string(_k); \ + if (!_t) \ + continue; \ + fputs_unlocked(_t, stdout); \ + fputc_unlocked('\n', stdout); \ + } \ + funlockfile(stdout); \ + } while(false) diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c index a60c7dccfe..1747f35b25 100644 --- a/src/systemd/src/basic/string-util.c +++ b/src/systemd/src/basic/string-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -16,6 +11,7 @@ #include <string.h> #include "alloc-util.h" +#include "escape.h" #include "gunicode.h" #include "locale-util.h" #include "macro.h" @@ -271,23 +267,12 @@ char *strjoin_real(const char *x, ...) { } char *strstrip(char *s) { - char *e; - if (!s) return NULL; - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; + /* Drops trailing whitespace. Modifies the string in place. Returns pointer to first non-space character */ - return s; + return delete_trailing_chars(skip_leading_chars(s, WHITESPACE), WHITESPACE); } char *delete_chars(char *s, const char *bad) { @@ -458,9 +443,23 @@ bool string_has_cc(const char *p, const char *ok) { } #if 0 /* NM_IGNORED */ +static int write_ellipsis(char *buf, bool unicode) { + if (unicode || is_locale_utf8()) { + buf[0] = 0xe2; /* tri-dot ellipsis: … */ + buf[1] = 0x80; + buf[2] = 0xa6; + } else { + buf[0] = '.'; + buf[1] = '.'; + buf[2] = '.'; + } + + return 3; +} + static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x, need_space; - char *r; + size_t x, need_space, suffix_len; + char *t; assert(s); assert(percent <= 100); @@ -496,8 +495,8 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le * either for the UTF-8 encoded character or for three ASCII characters. */ need_space = is_locale_utf8() ? 1 : 3; - r = new(char, new_length+3); - if (!r) + t = new(char, new_length+3); + if (!t) return NULL; assert(new_length >= need_space); @@ -505,23 +504,13 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le x = ((new_length - need_space) * percent + 50) / 100; assert(x <= new_length - need_space); - memcpy(r, s, x); - - if (is_locale_utf8()) { - r[x+0] = 0xe2; /* tri-dot ellipsis: … */ - r[x+1] = 0x80; - r[x+2] = 0xa6; - } else { - r[x+0] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; - } - - memcpy(r + x + 3, - s + old_length - (new_length - x - need_space), - new_length - x - need_space + 1); + memcpy(t, s, x); + write_ellipsis(t + x, false); + suffix_len = new_length - x - need_space; + memcpy(t + x + 3, s + old_length - suffix_len, suffix_len); + *(t + x + 3 + suffix_len) = '\0'; - return r; + return t; } char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { @@ -552,42 +541,56 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne return strdup(""); /* If no multibyte characters use ascii_ellipsize_mem for speed */ - if (ascii_is_valid(s)) + if (ascii_is_valid_n(s, old_length)) return ascii_ellipsize_mem(s, old_length, new_length, percent); x = ((new_length - 1) * percent) / 100; assert(x <= new_length - 1); k = 0; - for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + for (i = s; i < s + old_length; i = utf8_next_char(i)) { char32_t c; + int w; r = utf8_encoded_to_unichar(i, &c); if (r < 0) return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - if (k > x) /* last character was wide and went over quota */ - x++; + w = unichar_iswide(c) ? 2 : 1; + if (k + w <= x) + k += w; + else + break; + } - for (j = s + old_length; k < new_length && j > i; ) { + for (j = s + old_length; j > i; ) { char32_t c; + int w; + const char *jj; - j = utf8_prev_char(j); - r = utf8_encoded_to_unichar(j, &c); + jj = utf8_prev_char(j); + r = utf8_encoded_to_unichar(jj, &c); if (r < 0) return NULL; - k += unichar_iswide(c) ? 2 : 1; + + w = unichar_iswide(c) ? 2 : 1; + if (k + w <= new_length) { + k += w; + j = jj; + } else + break; } assert(i <= j); /* we don't actually need to ellipsize */ if (i == j) - return memdup(s, old_length + 1); + return memdup_suffix0(s, old_length); - /* make space for ellipsis */ - j = utf8_next_char(j); + /* make space for ellipsis, if possible */ + if (j < s + old_length) + j = utf8_next_char(j); + else if (i > s) + i = utf8_prev_char(i); len = i - s; len2 = s + old_length - j; @@ -601,21 +604,81 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne */ memcpy(e, s, len); - e[len + 0] = 0xe2; /* tri-dot ellipsis: … */ - e[len + 1] = 0x80; - e[len + 2] = 0xa6; - - memcpy(e + len + 3, j, len2 + 1); + write_ellipsis(e + len, true); + memcpy(e + len + 3, j, len2); + *(e + len + 3 + len2) = '\0'; return e; } -char *ellipsize(const char *s, size_t length, unsigned percent) { +char *cellescape(char *buf, size_t len, const char *s) { + /* Escape and ellipsize s into buffer buf of size len. Only non-control ASCII + * characters are copied as they are, everything else is escaped. The result + * is different then if escaping and ellipsization was performed in two + * separate steps, because each sequence is either stored in full or skipped. + * + * This function should be used for logging about strings which expected to + * be plain ASCII in a safe way. + * + * An ellipsis will be used if s is too long. It was always placed at the + * very end. + */ - if (length == (size_t) -1) - return strdup(s); + size_t i = 0, last_char_width[4] = {}, k = 0, j; + + assert(len > 0); /* at least a terminating NUL */ + + for (;;) { + char four[4]; + int w; + + if (*s == 0) /* terminating NUL detected? then we are done! */ + goto done; + + w = cescape_char(*s, four); + if (i + w + 1 > len) /* This character doesn't fit into the buffer anymore? In that case let's + * ellipsize at the previous location */ + break; + + /* OK, there was space, let's add this escaped character to the buffer */ + memcpy(buf + i, four, w); + i += w; + + /* And remember its width in the ring buffer */ + last_char_width[k] = w; + k = (k + 1) % 4; + + s++; + } + + /* Ellipsation is necessary. This means we might need to truncate the string again to make space for 4 + * characters ideally, but the buffer is shorter than that in the first place take what we can get */ + for (j = 0; j < ELEMENTSOF(last_char_width); j++) { + + if (i + 4 <= len) /* nice, we reached our space goal */ + break; + + k = k == 0 ? 3 : k - 1; + if (last_char_width[k] == 0) /* bummer, we reached the beginning of the strings */ + break; + + assert(i >= last_char_width[k]); + i -= last_char_width[k]; + } + + if (i + 4 <= len) /* yay, enough space */ + i += write_ellipsis(buf + i, false); + else if (i + 3 <= len) { /* only space for ".." */ + buf[i++] = '.'; + buf[i++] = '.'; + } else if (i + 2 <= len) /* only space for a single "." */ + buf[i++] = '.'; + else + assert(i + 1 <= len); - return ellipsize_mem(s, strlen(s), length, percent); + done: + buf[i] = '\0'; + return buf; } #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index 5a10eeabfe..c0cc4e78d7 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <alloca.h> #include <stdbool.h> #include <stddef.h> @@ -156,7 +150,14 @@ static inline bool _pure_ in_charset(const char *s, const char* charset) { bool string_has_cc(const char *p, const char *ok) _pure_; char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent); -char *ellipsize(const char *s, size_t length, unsigned percent); +static inline char *ellipsize(const char *s, size_t length, unsigned percent) { + return ellipsize_mem(s, strlen(s), length, percent); +} + +char *cellescape(char *buf, size_t len, const char *s); + +/* This limit is arbitrary, enough to give some idea what the string contains */ +#define CELLESCAPE_DEFAULT_LENGTH 64 bool nulstr_contains(const char *nulstr, const char *needle); @@ -209,3 +210,21 @@ static inline size_t strlen_ptr(const char *s) { return strlen(s); } + +/* Like startswith(), but operates on arbitrary memory blocks */ +static inline void *memory_startswith(const void *p, size_t sz, const char *token) { + size_t n; + + assert(token); + + n = strlen(token); + if (sz < n) + return NULL; + + assert(p); + + if (memcmp(p, token, n) != 0) + return NULL; + + return (uint8_t*) p + n; +} diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index 9d5000aac1..9da8ceceb7 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index 958c5f3a98..51d03db940 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <fnmatch.h> #include <stdarg.h> #include <stdbool.h> diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index fa9f66f2ae..aafa03757a 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -285,8 +280,11 @@ static char *format_timestamp_internal( return NULL; /* Timestamp is unset */ /* Let's not format times with years > 9999 */ - if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) - return NULL; + if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) { + assert(l >= strlen("--- XXXX-XX-XX XX:XX:XX") + 1); + strcpy(buf, "--- XXXX-XX-XX XX:XX:XX"); + return buf; + } sec = (time_t) (t / USEC_PER_SEC); /* Round down */ @@ -485,7 +483,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { /* Let's see if we should shows this in dot notation */ if (t < USEC_PER_MINUTE && b > 0) { usec_t cc; - int j; + signed char j; j = 0; for (cc = table[i].usec; cc > 1; cc /= 10) @@ -1314,6 +1312,9 @@ bool timezone_is_valid(const char *name, int log_level) { if (slash) return false; + if (p - name >= PATH_MAX) + return false; + t = strjoina("/usr/share/zoneinfo/", name); fd = open(t, O_RDONLY|O_CLOEXEC); @@ -1467,4 +1468,28 @@ bool in_utc_timezone(void) { return timezone == 0 && daylight == 0; } + +int time_change_fd(void) { + + /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */ + static const struct itimerspec its = { + .it_value.tv_sec = TIME_T_MAX, + }; + + _cleanup_close_ int fd; + + assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX)); + + /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to + * CLOCK_MONOTONIC. */ + + fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + return -errno; + + if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) + return -errno; + + return TAKE_FD(fd); +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index e720688c2b..344f2dc52e 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <inttypes.h> #include <stdbool.h> #include <stddef.h> @@ -183,5 +177,7 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { /* With a 32bit time_t we can't go beyond 2038... */ #define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000) #else -#error "Yuck, time_t is neither 4 not 8 bytes wide?" +#error "Yuck, time_t is neither 4 nor 8 bytes wide?" #endif + +int time_change_fd(void); diff --git a/src/systemd/src/basic/umask-util.h b/src/systemd/src/basic/umask-util.h index ce705247d6..e964292eaf 100644 --- a/src/systemd/src/basic/umask-util.h +++ b/src/systemd/src/basic/umask-util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <stdbool.h> #include <sys/stat.h> #include <sys/types.h> diff --git a/src/systemd/src/basic/utf8.c b/src/systemd/src/basic/utf8.c index 7a382204f2..80de43c572 100644 --- a/src/systemd/src/basic/utf8.c +++ b/src/systemd/src/basic/utf8.c @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2008-2011 Kay Sievers - Copyright 2012 Lennart Poettering + Copyright © 2008-2011 Kay Sievers ***/ /* Parts of this file are based on the GLIB utf8 validation functions. The @@ -249,6 +246,9 @@ char *utf8_escape_non_printable(const char *str) { char *ascii_is_valid(const char *str) { const char *p; + /* Check whether the string consists of valid ASCII bytes, + * i.e values between 0 and 127, inclusive. */ + assert(str); for (p = str; *p; p++) @@ -258,6 +258,21 @@ char *ascii_is_valid(const char *str) { return (char*) str; } +char *ascii_is_valid_n(const char *str, size_t len) { + size_t i; + + /* Very similar to ascii_is_valid(), but checks exactly len + * bytes and rejects any NULs in that range. */ + + assert(str); + + for (i = 0; i < len; i++) + if ((unsigned char) str[i] >= 128 || str[i] == 0) + return NULL; + + return (char*) str; +} + /** * utf8_encode_unichar() - Encode single UCS-4 character as UTF-8 * @out_utf8: output buffer of at least 4 bytes or NULL diff --git a/src/systemd/src/basic/utf8.h b/src/systemd/src/basic/utf8.h index 0ebe36d96b..f37f87ffe6 100644 --- a/src/systemd/src/basic/utf8.h +++ b/src/systemd/src/basic/utf8.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering -***/ - #include <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -24,6 +18,7 @@ bool unichar_is_valid(char32_t c); const char *utf8_is_valid(const char *s) _pure_; char *ascii_is_valid(const char *s) _pure_; +char *ascii_is_valid_n(const char *str, size_t len); bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 12e2f45115..ba7474f0bb 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ #include "nm-sd-adapt.h" @@ -269,7 +264,7 @@ int container_get_leader(const char *machine, pid_t *pid) { return -EINVAL; p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); + r = parse_env_file(NULL, p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); if (r == -ENOENT) return -EHOSTDOWN; if (r < 0) @@ -410,6 +405,7 @@ uint64_t physical_memory(void) { uint64_t mem, lim; size_t ps; long sc; + int r; /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of * memory. @@ -423,13 +419,40 @@ uint64_t physical_memory(void) { ps = page_size(); mem = (uint64_t) sc * (uint64_t) ps; - if (cg_get_root_path(&root) < 0) + r = cg_get_root_path(&root); + if (r < 0) { + log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m"); return mem; + } - if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value)) + r = cg_all_unified(); + if (r < 0) { + log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m"); return mem; + } + if (r > 0) { + r = cg_get_attribute("memory", root, "memory.max", &value); + if (r < 0) { + log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m"); + return mem; + } + + if (streq(value, "max")) + return mem; + } else { + r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value); + if (r < 0) { + log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m"); + return mem; + } + } - if (safe_atou64(value, &lim) < 0) + r = safe_atou64(value, &lim); + if (r < 0) { + log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value); + return mem; + } + if (lim == UINT64_MAX) return mem; /* Make sure the limit is a multiple of our own page size */ @@ -470,6 +493,7 @@ uint64_t system_tasks_max(void) { uint64_t a = TASKS_MAX, b = TASKS_MAX; _cleanup_free_ char *root = NULL; + int r; /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this * limit: @@ -480,13 +504,24 @@ uint64_t system_tasks_max(void) { * * And then pick the smallest of the three */ - (void) procfs_tasks_get_limit(&a); + r = procfs_tasks_get_limit(&a); + if (r < 0) + log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m"); - if (cg_get_root_path(&root) >= 0) { + r = cg_get_root_path(&root); + if (r < 0) + log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m"); + else { _cleanup_free_ char *value = NULL; - if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) - (void) safe_atou64(value, &b); + r = cg_get_attribute("pids", root, "pids.max", &value); + if (r < 0) + log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m"); + else if (!streq(value, "max")) { + r = safe_atou64(value, &b); + if (r < 0) + log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m"); + } } return MIN3(TASKS_MAX, diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index ad1931f7b6..9699d228f9 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering -***/ - #include <alloca.h> #include <errno.h> #include <fcntl.h> diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index 26db7ea871..1b711c950d 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Axis Communications AB. All rights reserved. - Copyright (C) 2015 Tom Gundersen + Copyright © 2014 Axis Communications AB. All rights reserved. + Copyright © 2015 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/arp-util.h b/src/systemd/src/libsystemd-network/arp-util.h index 86864e9fd5..10c684864b 100644 --- a/src/systemd/src/libsystemd-network/arp-util.h +++ b/src/systemd/src/libsystemd-network/arp-util.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2014 Axis Communications AB. All rights reserved. + Copyright © 2014 Axis Communications AB. All rights reserved. ***/ #include <netinet/if_ether.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 6f8adfa610..753573676c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2015 Tom Gundersen <teg@jklmen> + Copyright © 2015 Tom Gundersen <teg@jklmen> ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h index c0a10b6c35..42d4956d10 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.h +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2015 Tom Gundersen <teg@jklmen> + Copyright © 2015 Tom Gundersen <teg@jklmen> ***/ #include "sd-id128.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index f827622233..257a3c2e2f 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -2,10 +2,8 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen + Copyright © 2013 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen ***/ #include <linux/if_packet.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index 66c213e28c..fabac183ef 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -2,10 +2,8 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen + Copyright © 2013 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen ***/ #include <stdint.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 37c1ba193d..90fe29d046 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright © 2013 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 86e67358c3..4a4f7de020 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright © 2013 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 136bab9d60..214aed8e82 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen + Copyright © 2013 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-protocol.h b/src/systemd/src/libsystemd-network/dhcp-protocol.h index 2230e094d0..f03663248a 100644 --- a/src/systemd/src/libsystemd-network/dhcp-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp-protocol.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright © 2013 Intel Corporation. All rights reserved. ***/ #include <netinet/ip.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index 33c4332081..f1cbd6a4f1 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ #include <net/ethernet.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h index 2bf5499770..dc85c437c9 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -2,10 +2,8 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen + Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ #include <stdint.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index 2c6dc7131d..98aa6261eb 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright © 2014 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index 87ae96a203..a8a56463a5 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" @@ -143,7 +141,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { } int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { - uint8_t buffer[1 + DNS_WIRE_FOMAT_HOSTNAME_MAX]; + uint8_t buffer[1 + DNS_WIRE_FORMAT_HOSTNAME_MAX]; int r; assert_return(buf && *buf && buflen && fqdn, -EINVAL); diff --git a/src/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/systemd/src/libsystemd-network/dhcp6-protocol.h index 18417062d3..ffae4453ac 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp6-protocol.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright © 2014 Intel Corporation. All rights reserved. ***/ #include <netinet/ip6.h> diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h index 06cf7e8dad..e56509884e 100644 --- a/src/systemd/src/libsystemd-network/lldp-internal.h +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -2,10 +2,8 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright © 2014 Tom Gundersen + Copyright © 2014 Susant Sahani ***/ #include "sd-event.h" diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index 373e34c8eb..c28c995637 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -1,9 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.h b/src/systemd/src/libsystemd-network/lldp-neighbor.h index fae49c590f..494bc51760 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.h +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.h @@ -1,12 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering -***/ - #include <inttypes.h> #include <stdbool.h> #include <sys/types.h> diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index 307cf6c394..bc6c20d1fd 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright © 2014 Tom Gundersen + Copyright © 2014 Susant Sahani ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/lldp-network.h b/src/systemd/src/libsystemd-network/lldp-network.h index 7a1e8b101a..1d773acc2d 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.h +++ b/src/systemd/src/libsystemd-network/lldp-network.h @@ -2,10 +2,8 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright © 2014 Tom Gundersen + Copyright © 2014 Susant Sahani ***/ #include "sd-event.h" diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index e05f52d454..308762ee75 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen <teg@jklm.no> + Copyright © 2013 Tom Gundersen <teg@jklm.no> ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index d0076f453d..ef69e70155 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -2,9 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen <teg@jklm.no> + Copyright © 2013 Tom Gundersen <teg@jklm.no> ***/ #include <stdbool.h> @@ -12,6 +10,7 @@ #include "sd-dhcp-lease.h" #include "condition.h" +#include "conf-parser.h" #include "set.h" #include "udev.h" @@ -35,33 +34,15 @@ bool net_match_config(Set *match_mac, const char *dev_type, const char *dev_name); -int config_parse_net_condition(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_hwaddr(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_hwaddrs(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_ifnames(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_ifalias(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_iaid(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_bridge_port_priority(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); +#if 0 /* NM_IGNORED */ +CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); +CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); +CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); +CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); +CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); +CONFIG_PARSER_PROTOTYPE(config_parse_iaid); +CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); +#endif /* NM_IGNORED */ int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index ef2620f437..c2f81e1c40 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright © 2013 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index d92c512604..33a0796a83 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen + Copyright © 2013 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen ***/ #include "nm-sd-adapt.h" @@ -1036,7 +1034,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (r < 0) return r; - r = parse_env_file(lease_file, NEWLINE, + r = parse_env_file(NULL, lease_file, NEWLINE, "ADDRESS", &address, "ROUTER", &router, "NETMASK", &netmask, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index 1cec602281..ca03f580e7 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 3952cd99f0..1c8346d40f 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen + Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index ed98c0b628..3766c1f3ff 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Axis Communications AB. All rights reserved. - Copyright (C) 2015 Tom Gundersen + Copyright © 2014 Axis Communications AB. All rights reserved. + Copyright © 2015 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 001ebbd8b0..ca1e0bdb7c 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Axis Communications AB. All rights reserved. - Copyright (C) 2015 Tom Gundersen + Copyright © 2014 Axis Communications AB. All rights reserved. + Copyright © 2015 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index d88a0c6f2d..ea1dda4d17 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -1,9 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright © 2014 Tom Gundersen + Copyright © 2014 Susant Sahani ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 8a9b805501..f4d5dbe4b3 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -1,8 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering ***/ #include "nm-sd-adapt.h" @@ -17,6 +14,7 @@ #include "alloc-util.h" #include "fd-util.h" +#include "fs-util.h" #include "hashmap.h" #include "list.h" #include "macro.h" @@ -45,6 +43,7 @@ typedef enum EventSourceType { SOURCE_POST, SOURCE_EXIT, SOURCE_WATCHDOG, + SOURCE_INOTIFY, _SOURCE_EVENT_SOURCE_TYPE_MAX, _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 } EventSourceType; @@ -62,6 +61,7 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] [SOURCE_POST] = "post", [SOURCE_EXIT] = "exit", [SOURCE_WATCHDOG] = "watchdog", + [SOURCE_INOTIFY] = "inotify", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); @@ -73,12 +73,15 @@ typedef enum WakeupType { WAKEUP_EVENT_SOURCE, WAKEUP_CLOCK_DATA, WAKEUP_SIGNAL_DATA, + WAKEUP_INOTIFY_DATA, _WAKEUP_TYPE_MAX, _WAKEUP_TYPE_INVALID = -1, } WakeupType; #define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) +struct inode_data; + struct sd_event_source { WakeupType wakeup; @@ -102,6 +105,8 @@ struct sd_event_source { uint64_t pending_iteration; uint64_t prepare_iteration; + sd_event_destroy_t destroy_callback; + LIST_FIELDS(sd_event_source, sources); union { @@ -140,6 +145,12 @@ struct sd_event_source { sd_event_handler_t callback; unsigned prioq_index; } exit; + struct { + sd_event_inotify_handler_t callback; + uint32_t mask; + struct inode_data *inode_data; + LIST_FIELDS(sd_event_source, by_inode_data); + } inotify; }; }; @@ -174,6 +185,64 @@ struct signal_data { sd_event_source *current; }; +/* A structure listing all event sources currently watching a specific inode */ +struct inode_data { + /* The identifier for the inode, the combination of the .st_dev + .st_ino fields of the file */ + ino_t ino; + dev_t dev; + + /* An fd of the inode to watch. The fd is kept open until the next iteration of the loop, so that we can + * rearrange the priority still until then, as we need the original inode to change the priority as we need to + * add a watch descriptor to the right inotify for the priority which we can only do if we have a handle to the + * original inode. We keep a list of all inode_data objects with an open fd in the to_close list (see below) of + * the sd-event object, so that it is efficient to close everything, before entering the next event loop + * iteration. */ + int fd; + + /* The inotify "watch descriptor" */ + int wd; + + /* The combination of the mask of all inotify watches on this inode we manage. This is also the mask that has + * most recently been set on the watch descriptor. */ + uint32_t combined_mask; + + /* All event sources subscribed to this inode */ + LIST_HEAD(sd_event_source, event_sources); + + /* The inotify object we watch this inode with */ + struct inotify_data *inotify_data; + + /* A linked list of all inode data objects with fds to close (see above) */ + LIST_FIELDS(struct inode_data, to_close); +}; + +/* A structure encapsulating an inotify fd */ +struct inotify_data { + WakeupType wakeup; + + /* For each priority we maintain one inotify fd, so that we only have to dequeue a single event per priority at + * a time */ + + int fd; + int64_t priority; + + Hashmap *inodes; /* The inode_data structures keyed by dev+ino */ + Hashmap *wd; /* The inode_data structures keyed by the watch descriptor for each */ + + /* The buffer we read inotify events into */ + union inotify_event_buffer buffer; + size_t buffer_filled; /* fill level of the buffer */ + + /* How many event sources are currently marked pending for this inotify. We won't read new events off the + * inotify fd as long as there are still pending events on the inotify (because we have no strategy of queuing + * the events locally if they can't be coalesced). */ + unsigned n_pending; + + /* A linked list of all inotify objects with data already read, that still need processing. We keep this list + * to make it efficient to figure out what inotify objects to process data on next. */ + LIST_FIELDS(struct inotify_data, buffered); +}; + struct sd_event { unsigned n_ref; @@ -204,6 +273,14 @@ struct sd_event { Prioq *exit; + Hashmap *inotify_data; /* indexed by priority */ + + /* A list of inode structures that still have an fd open, that we need to close before the next loop iteration */ + LIST_HEAD(struct inode_data, inode_data_to_close); + + /* A list of inotify objects that already have events buffered which aren't processed yet */ + LIST_HEAD(struct inotify_data, inotify_data_buffered); + pid_t original_pid; uint64_t iteration; @@ -233,6 +310,7 @@ struct sd_event { static thread_local sd_event *default_event = NULL; static void source_disconnect(sd_event_source *s); +static void event_gc_inode_data(sd_event *e, struct inode_data *d); static sd_event *event_resolve(sd_event *e) { return e == SD_EVENT_DEFAULT ? default_event : e; @@ -414,6 +492,8 @@ static void event_free(sd_event *e) { free(e->signal_sources); hashmap_free(e->signal_data); + hashmap_free(e->inotify_data); + hashmap_free(e->child_sources); set_free(e->post_sources); free(e); @@ -425,16 +505,32 @@ _public_ int sd_event_new(sd_event** ret) { assert_return(ret, -EINVAL); - e = new0(sd_event, 1); + e = new(sd_event, 1); if (!e) return -ENOMEM; - e->n_ref = 1; - e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1; - e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY; - e->realtime.wakeup = e->boottime.wakeup = e->monotonic.wakeup = e->realtime_alarm.wakeup = e->boottime_alarm.wakeup = WAKEUP_CLOCK_DATA; - e->original_pid = getpid_cached(); - e->perturb = USEC_INFINITY; + *e = (sd_event) { + .n_ref = 1, + .epoll_fd = -1, + .watchdog_fd = -1, + .realtime.wakeup = WAKEUP_CLOCK_DATA, + .realtime.fd = -1, + .realtime.next = USEC_INFINITY, + .boottime.wakeup = WAKEUP_CLOCK_DATA, + .boottime.fd = -1, + .boottime.next = USEC_INFINITY, + .monotonic.wakeup = WAKEUP_CLOCK_DATA, + .monotonic.fd = -1, + .monotonic.next = USEC_INFINITY, + .realtime_alarm.wakeup = WAKEUP_CLOCK_DATA, + .realtime_alarm.fd = -1, + .realtime_alarm.next = USEC_INFINITY, + .boottime_alarm.wakeup = WAKEUP_CLOCK_DATA, + .boottime_alarm.fd = -1, + .boottime_alarm.next = USEC_INFINITY, + .perturb = USEC_INFINITY, + .original_pid = getpid_cached(), + }; r = prioq_ensure_allocated(&e->pending, pending_prioq_compare); if (r < 0) @@ -520,18 +616,17 @@ static int source_io_register( int enabled, uint32_t events) { - struct epoll_event ev = {}; + struct epoll_event ev; int r; assert(s); assert(s->type == SOURCE_IO); assert(enabled != SD_EVENT_OFF); - ev.events = events; - ev.data.ptr = s; - - if (enabled == SD_EVENT_ONESHOT) - ev.events |= EPOLLONESHOT; + ev = (struct epoll_event) { + .events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), + .data.ptr = s, + }; if (s->io.registered) r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev); @@ -623,7 +718,7 @@ static int event_make_signal_data( int sig, struct signal_data **ret) { - struct epoll_event ev = {}; + struct epoll_event ev; struct signal_data *d; bool added = false; sigset_t ss_copy; @@ -638,7 +733,7 @@ static int event_make_signal_data( if (e->signal_sources && e->signal_sources[sig]) priority = e->signal_sources[sig]->priority; else - priority = 0; + priority = SD_EVENT_PRIORITY_NORMAL; d = hashmap_get(e->signal_data, &priority); if (d) { @@ -652,13 +747,15 @@ static int event_make_signal_data( if (r < 0) return r; - d = new0(struct signal_data, 1); + d = new(struct signal_data, 1); if (!d) return -ENOMEM; - d->wakeup = WAKEUP_SIGNAL_DATA; - d->fd = -1; - d->priority = priority; + *d = (struct signal_data) { + .wakeup = WAKEUP_SIGNAL_DATA, + .fd = -1, + .priority = priority, + }; r = hashmap_put(e->signal_data, &d->priority, d); if (r < 0) { @@ -688,8 +785,10 @@ static int event_make_signal_data( d->fd = fd_move_above_stdio(r); - ev.events = EPOLLIN; - ev.data.ptr = d; + ev = (struct epoll_event) { + .events = EPOLLIN, + .data.ptr = d, + }; r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev); if (r < 0) { @@ -856,6 +955,41 @@ static void source_disconnect(sd_event_source *s) { prioq_remove(s->event->exit, s, &s->exit.prioq_index); break; + case SOURCE_INOTIFY: { + struct inode_data *inode_data; + + inode_data = s->inotify.inode_data; + if (inode_data) { + struct inotify_data *inotify_data; + assert_se(inotify_data = inode_data->inotify_data); + + /* Detach this event source from the inode object */ + LIST_REMOVE(inotify.by_inode_data, inode_data->event_sources, s); + s->inotify.inode_data = NULL; + + if (s->pending) { + assert(inotify_data->n_pending > 0); + inotify_data->n_pending--; + } + + /* Note that we don't reduce the inotify mask for the watch descriptor here if the inode is + * continued to being watched. That's because inotify doesn't really have an API for that: we + * can only change watch masks with access to the original inode either by fd or by path. But + * paths aren't stable, and keeping an O_PATH fd open all the time would mean wasting an fd + * continously and keeping the mount busy which we can't really do. We could reconstruct the + * original inode from /proc/self/fdinfo/$INOTIFY_FD (as all watch descriptors are listed + * there), but given the need for open_by_handle_at() which is privileged and not universally + * available this would be quite an incomplete solution. Hence we go the other way, leave the + * mask set, even if it is not minimized now, and ignore all events we aren't interested in + * anymore after reception. Yes, this sucks, but … Linux … */ + + /* Maybe release the inode data (and its inotify) */ + event_gc_inode_data(s->event, inode_data); + } + + break; + } + default: assert_not_reached("Wut? I shouldn't exist."); } @@ -883,7 +1017,10 @@ static void source_free(sd_event_source *s) { source_disconnect(s); if (s->type == SOURCE_IO && s->io.owned) - safe_close(s->io.fd); + s->io.fd = safe_close(s->io.fd); + + if (s->destroy_callback) + s->destroy_callback(s->userdata); free(s->description); free(s); @@ -930,6 +1067,19 @@ static int source_set_pending(sd_event_source *s, bool b) { d->current = NULL; } + if (s->type == SOURCE_INOTIFY) { + + assert(s->inotify.inode_data); + assert(s->inotify.inode_data->inotify_data); + + if (b) + s->inotify.inode_data->inotify_data->n_pending ++; + else { + assert(s->inotify.inode_data->inotify_data->n_pending > 0); + s->inotify.inode_data->inotify_data->n_pending --; + } + } + return 0; } @@ -938,15 +1088,18 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t assert(e); - s = new0(sd_event_source, 1); + s = new(sd_event_source, 1); if (!s) return NULL; - s->n_ref = 1; - s->event = e; - s->floating = floating; - s->type = type; - s->pending_index = s->prepare_index = PRIOQ_IDX_NULL; + *s = (struct sd_event_source) { + .n_ref = 1, + .event = e, + .floating = floating, + .type = type, + .pending_index = PRIOQ_IDX_NULL, + .prepare_index = PRIOQ_IDX_NULL, + }; if (!floating) sd_event_ref(e); @@ -1023,7 +1176,7 @@ static int event_setup_timer_fd( struct clock_data *d, clockid_t clock) { - struct epoll_event ev = {}; + struct epoll_event ev; int r, fd; assert(e); @@ -1038,8 +1191,10 @@ static int event_setup_timer_fd( fd = fd_move_above_stdio(fd); - ev.events = EPOLLIN; - ev.data.ptr = d; + ev = (struct epoll_event) { + .events = EPOLLIN, + .data.ptr = d, + }; r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev); if (r < 0) { @@ -1378,6 +1533,405 @@ _public_ int sd_event_add_exit( return 0; } +static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { + assert(e); + + if (!d) + return; + + assert(hashmap_isempty(d->inodes)); + assert(hashmap_isempty(d->wd)); + + if (d->buffer_filled > 0) + LIST_REMOVE(buffered, e->inotify_data_buffered, d); + + hashmap_free(d->inodes); + hashmap_free(d->wd); + + assert_se(hashmap_remove(e->inotify_data, &d->priority) == d); + + if (d->fd >= 0) { + if (epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) + log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m"); + + safe_close(d->fd); + } + free(d); +} + +static int event_make_inotify_data( + sd_event *e, + int64_t priority, + struct inotify_data **ret) { + + _cleanup_close_ int fd = -1; + struct inotify_data *d; + struct epoll_event ev; + int r; + + assert(e); + + d = hashmap_get(e->inotify_data, &priority); + if (d) { + if (ret) + *ret = d; + return 0; + } + + fd = inotify_init1(IN_NONBLOCK|O_CLOEXEC); + if (fd < 0) + return -errno; + + fd = fd_move_above_stdio(fd); + + r = hashmap_ensure_allocated(&e->inotify_data, &uint64_hash_ops); + if (r < 0) + return r; + + d = new(struct inotify_data, 1); + if (!d) + return -ENOMEM; + + *d = (struct inotify_data) { + .wakeup = WAKEUP_INOTIFY_DATA, + .fd = TAKE_FD(fd), + .priority = priority, + }; + + r = hashmap_put(e->inotify_data, &d->priority, d); + if (r < 0) { + d->fd = safe_close(d->fd); + free(d); + return r; + } + + ev = (struct epoll_event) { + .events = EPOLLIN, + .data.ptr = d, + }; + + if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev) < 0) { + r = -errno; + d->fd = safe_close(d->fd); /* let's close this ourselves, as event_free_inotify_data() would otherwise + * remove the fd from the epoll first, which we don't want as we couldn't + * add it in the first place. */ + event_free_inotify_data(e, d); + return r; + } + + if (ret) + *ret = d; + + return 1; +} + +static int inode_data_compare(const void *a, const void *b) { + const struct inode_data *x = a, *y = b; + + assert(x); + assert(y); + + if (x->dev < y->dev) + return -1; + if (x->dev > y->dev) + return 1; + + if (x->ino < y->ino) + return -1; + if (x->ino > y->ino) + return 1; + + return 0; +} + +static void inode_data_hash_func(const void *p, struct siphash *state) { + const struct inode_data *d = p; + + assert(p); + + siphash24_compress(&d->dev, sizeof(d->dev), state); + siphash24_compress(&d->ino, sizeof(d->ino), state); +} + +const struct hash_ops inode_data_hash_ops = { + .hash = inode_data_hash_func, + .compare = inode_data_compare +}; + +static void event_free_inode_data( + sd_event *e, + struct inode_data *d) { + + assert(e); + + if (!d) + return; + + assert(!d->event_sources); + + if (d->fd >= 0) { + LIST_REMOVE(to_close, e->inode_data_to_close, d); + safe_close(d->fd); + } + + if (d->inotify_data) { + + if (d->wd >= 0) { + if (d->inotify_data->fd >= 0) { + /* So here's a problem. At the time this runs the watch descriptor might already be + * invalidated, because an IN_IGNORED event might be queued right the moment we enter + * the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very + * likely case to happen. */ + + if (inotify_rm_watch(d->inotify_data->fd, d->wd) < 0 && errno != EINVAL) + log_debug_errno(errno, "Failed to remove watch descriptor %i from inotify, ignoring: %m", d->wd); + } + + assert_se(hashmap_remove(d->inotify_data->wd, INT_TO_PTR(d->wd)) == d); + } + + assert_se(hashmap_remove(d->inotify_data->inodes, d) == d); + } + + free(d); +} + +static void event_gc_inode_data( + sd_event *e, + struct inode_data *d) { + + struct inotify_data *inotify_data; + + assert(e); + + if (!d) + return; + + if (d->event_sources) + return; + + inotify_data = d->inotify_data; + event_free_inode_data(e, d); + + if (inotify_data && hashmap_isempty(inotify_data->inodes)) + event_free_inotify_data(e, inotify_data); +} + +static int event_make_inode_data( + sd_event *e, + struct inotify_data *inotify_data, + dev_t dev, + ino_t ino, + struct inode_data **ret) { + + struct inode_data *d, key; + int r; + + assert(e); + assert(inotify_data); + + key = (struct inode_data) { + .ino = ino, + .dev = dev, + }; + + d = hashmap_get(inotify_data->inodes, &key); + if (d) { + if (ret) + *ret = d; + + return 0; + } + + r = hashmap_ensure_allocated(&inotify_data->inodes, &inode_data_hash_ops); + if (r < 0) + return r; + + d = new(struct inode_data, 1); + if (!d) + return -ENOMEM; + + *d = (struct inode_data) { + .dev = dev, + .ino = ino, + .wd = -1, + .fd = -1, + .inotify_data = inotify_data, + }; + + r = hashmap_put(inotify_data->inodes, d, d); + if (r < 0) { + free(d); + return r; + } + + if (ret) + *ret = d; + + return 1; +} + +static uint32_t inode_data_determine_mask(struct inode_data *d) { + bool excl_unlink = true; + uint32_t combined = 0; + sd_event_source *s; + + assert(d); + + /* Combines the watch masks of all event sources watching this inode. We generally just OR them together, but + * the IN_EXCL_UNLINK flag is ANDed instead. + * + * Note that we add all sources to the mask here, regardless whether enabled, disabled or oneshot. That's + * because we cannot change the mask anymore after the event source was created once, since the kernel has no + * API for that. Hence we need to subscribe to the maximum mask we ever might be interested in, and supress + * events we don't care for client-side. */ + + LIST_FOREACH(inotify.by_inode_data, s, d->event_sources) { + + if ((s->inotify.mask & IN_EXCL_UNLINK) == 0) + excl_unlink = false; + + combined |= s->inotify.mask; + } + + return (combined & ~(IN_ONESHOT|IN_DONT_FOLLOW|IN_ONLYDIR|IN_EXCL_UNLINK)) | (excl_unlink ? IN_EXCL_UNLINK : 0); +} + +static int inode_data_realize_watch(sd_event *e, struct inode_data *d) { + uint32_t combined_mask; + int wd, r; + + assert(d); + assert(d->fd >= 0); + + combined_mask = inode_data_determine_mask(d); + + if (d->wd >= 0 && combined_mask == d->combined_mask) + return 0; + + r = hashmap_ensure_allocated(&d->inotify_data->wd, NULL); + if (r < 0) + return r; + + wd = inotify_add_watch_fd(d->inotify_data->fd, d->fd, combined_mask); + if (wd < 0) + return -errno; + + if (d->wd < 0) { + r = hashmap_put(d->inotify_data->wd, INT_TO_PTR(wd), d); + if (r < 0) { + (void) inotify_rm_watch(d->inotify_data->fd, wd); + return r; + } + + d->wd = wd; + + } else if (d->wd != wd) { + + log_debug("Weird, the watch descriptor we already knew for this inode changed?"); + (void) inotify_rm_watch(d->fd, wd); + return -EINVAL; + } + + d->combined_mask = combined_mask; + return 1; +} + +_public_ int sd_event_add_inotify( + sd_event *e, + sd_event_source **ret, + const char *path, + uint32_t mask, + sd_event_inotify_handler_t callback, + void *userdata) { + + bool rm_inotify = false, rm_inode = false; + struct inotify_data *inotify_data = NULL; + struct inode_data *inode_data = NULL; + _cleanup_close_ int fd = -1; + sd_event_source *s; + struct stat st; + int r; + + assert_return(e, -EINVAL); + assert_return(e = event_resolve(e), -ENOPKG); + assert_return(path, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + /* Refuse IN_MASK_ADD since we coalesce watches on the same inode, and hence really don't want to merge + * masks. Or in other words, this whole code exists only to manage IN_MASK_ADD type operations for you, hence + * the user can't use them for us. */ + if (mask & IN_MASK_ADD) + return -EINVAL; + + fd = open(path, O_PATH|O_CLOEXEC| + (mask & IN_ONLYDIR ? O_DIRECTORY : 0)| + (mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0)); + if (fd < 0) + return -errno; + + if (fstat(fd, &st) < 0) + return -errno; + + s = source_new(e, !ret, SOURCE_INOTIFY); + if (!s) + return -ENOMEM; + + s->enabled = mask & IN_ONESHOT ? SD_EVENT_ONESHOT : SD_EVENT_ON; + s->inotify.mask = mask; + s->inotify.callback = callback; + s->userdata = userdata; + + /* Allocate an inotify object for this priority, and an inode object within it */ + r = event_make_inotify_data(e, SD_EVENT_PRIORITY_NORMAL, &inotify_data); + if (r < 0) + goto fail; + rm_inotify = r > 0; + + r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data); + if (r < 0) + goto fail; + rm_inode = r > 0; + + /* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of + * the event source, until then, for which we need the original inode. */ + if (inode_data->fd < 0) { + inode_data->fd = TAKE_FD(fd); + LIST_PREPEND(to_close, e->inode_data_to_close, inode_data); + } + + /* Link our event source to the inode data object */ + LIST_PREPEND(inotify.by_inode_data, inode_data->event_sources, s); + s->inotify.inode_data = inode_data; + + rm_inode = rm_inotify = false; + + /* Actually realize the watch now */ + r = inode_data_realize_watch(e, inode_data); + if (r < 0) + goto fail; + + (void) sd_event_source_set_description(s, path); + + if (ret) + *ret = s; + + return 0; + +fail: + source_free(s); + + if (rm_inode) + event_free_inode_data(e, inode_data); + + if (rm_inotify) + event_free_inotify_data(e, inotify_data); + + return r; +} + _public_ sd_event_source* sd_event_source_ref(sd_event_source *s) { if (!s) @@ -1532,6 +2086,10 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) if (s->io.events == events && !(events & EPOLLET)) return 0; + r = source_set_pending(s, false); + if (r < 0) + return r; + if (s->enabled != SD_EVENT_OFF) { r = source_io_register(s, s->enabled, events); if (r < 0) @@ -1539,7 +2097,6 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) } s->io.events = events; - source_set_pending(s, false); return 0; } @@ -1572,6 +2129,9 @@ _public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) } _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) { + bool rm_inotify = false, rm_inode = false; + struct inotify_data *new_inotify_data = NULL; + struct inode_data *new_inode_data = NULL; int r; assert_return(s, -EINVAL); @@ -1581,7 +2141,59 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) if (s->priority == priority) return 0; - if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { + if (s->type == SOURCE_INOTIFY) { + struct inode_data *old_inode_data; + + assert(s->inotify.inode_data); + old_inode_data = s->inotify.inode_data; + + /* We need the original fd to change the priority. If we don't have it we can't change the priority, + * anymore. Note that we close any fds when entering the next event loop iteration, i.e. for inotify + * events we allow priority changes only until the first following iteration. */ + if (old_inode_data->fd < 0) + return -EOPNOTSUPP; + + r = event_make_inotify_data(s->event, priority, &new_inotify_data); + if (r < 0) + return r; + rm_inotify = r > 0; + + r = event_make_inode_data(s->event, new_inotify_data, old_inode_data->dev, old_inode_data->ino, &new_inode_data); + if (r < 0) + goto fail; + rm_inode = r > 0; + + if (new_inode_data->fd < 0) { + /* Duplicate the fd for the new inode object if we don't have any yet */ + new_inode_data->fd = fcntl(old_inode_data->fd, F_DUPFD_CLOEXEC, 3); + if (new_inode_data->fd < 0) { + r = -errno; + goto fail; + } + + LIST_PREPEND(to_close, s->event->inode_data_to_close, new_inode_data); + } + + /* Move the event source to the new inode data structure */ + LIST_REMOVE(inotify.by_inode_data, old_inode_data->event_sources, s); + LIST_PREPEND(inotify.by_inode_data, new_inode_data->event_sources, s); + s->inotify.inode_data = new_inode_data; + + /* Now create the new watch */ + r = inode_data_realize_watch(s->event, new_inode_data); + if (r < 0) { + /* Move it back */ + LIST_REMOVE(inotify.by_inode_data, new_inode_data->event_sources, s); + LIST_PREPEND(inotify.by_inode_data, old_inode_data->event_sources, s); + s->inotify.inode_data = old_inode_data; + goto fail; + } + + s->priority = priority; + + event_gc_inode_data(s->event, old_inode_data); + + } else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { struct signal_data *old, *d; /* Move us from the signalfd belonging to the old @@ -1611,6 +2223,15 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); return 0; + +fail: + if (rm_inode) + event_free_inode_data(s->event, new_inode_data); + + if (rm_inotify) + event_free_inotify_data(s->event, new_inotify_data); + + return r; } _public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { @@ -1639,6 +2260,13 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { if (m == SD_EVENT_OFF) { + /* Unset the pending flag when this event source is disabled */ + if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + switch (s->type) { case SOURCE_IO: @@ -1685,6 +2313,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { case SOURCE_DEFER: case SOURCE_POST: + case SOURCE_INOTIFY: s->enabled = m; break; @@ -1693,6 +2322,14 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { } } else { + + /* Unset the pending flag when this event source is enabled */ + if (s->enabled == SD_EVENT_OFF && !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + switch (s->type) { case SOURCE_IO: @@ -1757,6 +2394,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { case SOURCE_DEFER: case SOURCE_POST: + case SOURCE_INOTIFY: s->enabled = m; break; @@ -1786,15 +2424,18 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { struct clock_data *d; + int r; assert_return(s, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); - s->time.next = usec; + r = source_set_pending(s, false); + if (r < 0) + return r; - source_set_pending(s, false); + s->time.next = usec; d = event_get_clock_data(s->event, s->type); assert(d); @@ -1818,6 +2459,7 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { struct clock_data *d; + int r; assert_return(s, -EINVAL); assert_return(usec != (uint64_t) -1, -EINVAL); @@ -1825,13 +2467,15 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); + r = source_set_pending(s, false); + if (r < 0) + return r; + if (usec == 0) usec = DEFAULT_ACCURACY_USEC; s->time.accuracy = usec; - source_set_pending(s, false); - d = event_get_clock_data(s->event, s->type); assert(d); @@ -1861,6 +2505,16 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { return 0; } +_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) { + assert_return(s, -EINVAL); + assert_return(mask, -EINVAL); + assert_return(s->type == SOURCE_INOTIFY, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *mask = s->inotify.mask; + return 0; +} + _public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) { int r; @@ -2194,6 +2848,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { int r; assert(e); + assert(d); assert_return(events == EPOLLIN, -EIO); /* If there's a signal queued on this priority and SIGCHLD is @@ -2250,6 +2905,160 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { } } +static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t revents) { + ssize_t n; + + assert(e); + assert(d); + + assert_return(revents == EPOLLIN, -EIO); + + /* If there's already an event source pending for this priority, don't read another */ + if (d->n_pending > 0) + return 0; + + /* Is the read buffer non-empty? If so, let's not read more */ + if (d->buffer_filled > 0) + return 0; + + n = read(d->fd, &d->buffer, sizeof(d->buffer)); + if (n < 0) { + if (IN_SET(errno, EAGAIN, EINTR)) + return 0; + + return -errno; + } + + assert(n > 0); + d->buffer_filled = (size_t) n; + LIST_PREPEND(buffered, e->inotify_data_buffered, d); + + return 1; +} + +static void event_inotify_data_drop(sd_event *e, struct inotify_data *d, size_t sz) { + assert(e); + assert(d); + assert(sz <= d->buffer_filled); + + if (sz == 0) + return; + + /* Move the rest to the buffer to the front, in order to get things properly aligned again */ + memmove(d->buffer.raw, d->buffer.raw + sz, d->buffer_filled - sz); + d->buffer_filled -= sz; + + if (d->buffer_filled == 0) + LIST_REMOVE(buffered, e->inotify_data_buffered, d); +} + +static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { + int r; + + assert(e); + assert(d); + + /* If there's already an event source pending for this priority, don't read another */ + if (d->n_pending > 0) + return 0; + + while (d->buffer_filled > 0) { + size_t sz; + + /* Let's validate that the event structures are complete */ + if (d->buffer_filled < offsetof(struct inotify_event, name)) + return -EIO; + + sz = offsetof(struct inotify_event, name) + d->buffer.ev.len; + if (d->buffer_filled < sz) + return -EIO; + + if (d->buffer.ev.mask & IN_Q_OVERFLOW) { + struct inode_data *inode_data; + Iterator i; + + /* The queue overran, let's pass this event to all event sources connected to this inotify + * object */ + + HASHMAP_FOREACH(inode_data, d->inodes, i) { + sd_event_source *s; + + LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { + + if (s->enabled == SD_EVENT_OFF) + continue; + + r = source_set_pending(s, true); + if (r < 0) + return r; + } + } + } else { + struct inode_data *inode_data; + sd_event_source *s; + + /* Find the inode object for this watch descriptor. If IN_IGNORED is set we also remove it from + * our watch descriptor table. */ + if (d->buffer.ev.mask & IN_IGNORED) { + + inode_data = hashmap_remove(d->wd, INT_TO_PTR(d->buffer.ev.wd)); + if (!inode_data) { + event_inotify_data_drop(e, d, sz); + continue; + } + + /* The watch descriptor was removed by the kernel, let's drop it here too */ + inode_data->wd = -1; + } else { + inode_data = hashmap_get(d->wd, INT_TO_PTR(d->buffer.ev.wd)); + if (!inode_data) { + event_inotify_data_drop(e, d, sz); + continue; + } + } + + /* Trigger all event sources that are interested in these events. Also trigger all event + * sources if IN_IGNORED or IN_UNMOUNT is set. */ + LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { + + if (s->enabled == SD_EVENT_OFF) + continue; + + if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 && + (s->inotify.mask & d->buffer.ev.mask & IN_ALL_EVENTS) == 0) + continue; + + r = source_set_pending(s, true); + if (r < 0) + return r; + } + } + + /* Something pending now? If so, let's finish, otherwise let's read more. */ + if (d->n_pending > 0) + return 1; + } + + return 0; +} + +static int process_inotify(sd_event *e) { + struct inotify_data *d; + int r, done = 0; + + assert(e); + + LIST_FOREACH(buffered, d, e->inotify_data_buffered) { + r = event_inotify_data_process(e, d); + if (r < 0) + return r; + if (r > 0) + done ++; + } + + return done; +} + static int source_dispatch(sd_event_source *s) { EventSourceType saved_type; int r = 0; @@ -2319,7 +3128,7 @@ static int source_dispatch(sd_event_source *s) { /* Now, reap the PID for good. */ if (zombie) - waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); + (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); break; } @@ -2336,6 +3145,28 @@ static int source_dispatch(sd_event_source *s) { r = s->exit.callback(s, s->userdata); break; + case SOURCE_INOTIFY: { + struct sd_event *e = s->event; + struct inotify_data *d; + size_t sz; + + assert(s->inotify.inode_data); + assert_se(d = s->inotify.inode_data->inotify_data); + + assert(d->buffer_filled >= offsetof(struct inotify_event, name)); + sz = offsetof(struct inotify_event, name) + d->buffer.ev.len; + assert(d->buffer_filled >= sz); + + r = s->inotify.callback(s, &d->buffer.ev, s->userdata); + + /* When no event is pending anymore on this inotify object, then let's drop the event from the + * buffer. */ + if (d->n_pending == 0) + event_inotify_data_drop(e, d, sz); + + break; + } + case SOURCE_WATCHDOG: case _SOURCE_EVENT_SOURCE_TYPE_MAX: case _SOURCE_EVENT_SOURCE_TYPE_INVALID: @@ -2470,6 +3301,25 @@ static int process_watchdog(sd_event *e) { return arm_watchdog(e); } +static void event_close_inode_data_fds(sd_event *e) { + struct inode_data *d; + + assert(e); + + /* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin + * filesystems. But we can't close them right-away as we need them as long as the user still wants to make + * adjustments to the even source, such as changing the priority (which requires us to remove and readd a watch + * for the inode). Hence, let's close them when entering the first iteration after they were added, as a + * compromise. */ + + while ((d = e->inode_data_to_close)) { + assert(d->fd >= 0); + d->fd = safe_close(d->fd); + + LIST_REMOVE(to_close, e->inode_data_to_close, d); + } +} + _public_ int sd_event_prepare(sd_event *e) { int r; @@ -2510,6 +3360,8 @@ _public_ int sd_event_prepare(sd_event *e) { if (r < 0) return r; + event_close_inode_data_fds(e); + if (event_next_pending(e) || e->need_process_child) goto pending; @@ -2545,6 +3397,10 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { ev_queue_max = MAX(e->n_sources, 1u); ev_queue = newa(struct epoll_event, ev_queue_max); + /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ + if (e->inotify_data_buffered) + timeout = 0; + m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max, timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC)); if (m < 0) { @@ -2582,6 +3438,10 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events); break; + case WAKEUP_INOTIFY_DATA: + r = event_inotify_data_read(e, ev_queue[i].data.ptr, ev_queue[i].events); + break; + default: assert_not_reached("Invalid wake-up pointer"); } @@ -2620,6 +3480,10 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { goto finish; } + r = process_inotify(e); + if (r < 0) + goto finish; + if (event_next_pending(e)) { e->state = SD_EVENT_PENDING; @@ -2858,7 +3722,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { return e->watchdog; if (b) { - struct epoll_event ev = {}; + struct epoll_event ev; r = sd_watchdog_enabled(false, &e->watchdog_period); if (r <= 0) @@ -2876,8 +3740,10 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { if (r < 0) goto fail; - ev.events = EPOLLIN; - ev.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG); + ev = (struct epoll_event) { + .events = EPOLLIN, + .data.ptr = INT_TO_PTR(SOURCE_WATCHDOG), + }; r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev); if (r < 0) { @@ -2916,4 +3782,20 @@ _public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { *ret = e->iteration; return 0; } + +_public_ int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback) { + assert_return(s, -EINVAL); + + s->destroy_callback = callback; + return 0; +} + +_public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret) { + assert_return(s, -EINVAL); + + if (ret) + *ret = s->destroy_callback; + + return !!s->destroy_callback; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index 26eef0fd6a..03a3869928 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -1,8 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 9aeb27a220..f0b4eca581 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -2,9 +2,6 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering ***/ #include <stdbool.h> diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index de0ae600f2..8fe8ff4335 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -1,8 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering ***/ #include "nm-sd-adapt.h" @@ -102,7 +99,7 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) { return r; if (sd_id128_is_null(saved_machine_id)) - return -EINVAL; + return -ENOMEDIUM; } *ret = saved_machine_id; diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index 3f41be621e..ab03404324 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -1,8 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering ***/ #include "nm-sd-adapt.h" @@ -360,10 +357,7 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) return -EINVAL; - if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1) - return 0; - - if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0) + if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX)) return 0; input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h index 47bd535756..8781eec65d 100644 --- a/src/systemd/src/shared/dns-domain.h +++ b/src/systemd/src/shared/dns-domain.h @@ -2,9 +2,6 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering ***/ #include <errno.h> @@ -25,7 +22,7 @@ #define DNS_HOSTNAME_MAX 253 /* Maximum length of a full hostname, on the wire, including the final NUL byte */ -#define DNS_WIRE_FOMAT_HOSTNAME_MAX 255 +#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255 /* Maximum number of labels per valid hostname */ #define DNS_N_LABELS_MAX 127 diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h index b4400e7b36..7b54d179eb 100644 --- a/src/systemd/src/systemd/_sd-common.h +++ b/src/systemd/src/systemd/_sd-common.h @@ -3,9 +3,6 @@ #define foosdcommonhfoo /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index fd0a569362..931b0e890b 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -3,9 +3,7 @@ #define foosddhcpclienthfoo /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. + 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 diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index 3cc7fcabe3..16c05661ec 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -3,10 +3,8 @@ #define foosddhcpleasehfoo /*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen + Copyright © 2013 Intel Corporation. All rights reserved. + Copyright © 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 diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index cadb32a051..4f3b2d9e2e 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -3,9 +3,7 @@ #define foosddhcp6clienthfoo /*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright © 2014 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 diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h index 22a5f8ce75..a673de5edd 100644 --- a/src/systemd/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -3,10 +3,8 @@ #define foosddhcp6leasehfoo /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + Copyright © 2014 Tom Gundersen + Copyright © 2014-2015 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 diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index ec4b7bcf69..7fcae4ac49 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -3,9 +3,6 @@ #define foosdeventhfoo /*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -24,6 +21,7 @@ #include <inttypes.h> #include <signal.h> #include <sys/epoll.h> +#include <sys/inotify.h> #include <sys/signalfd.h> #include <sys/types.h> #include <time.h> @@ -78,6 +76,8 @@ typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, #else typedef void* sd_event_child_handler_t; #endif +typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata); +typedef void (*sd_event_destroy_t)(void *userdata); int sd_event_default(sd_event **e); @@ -89,6 +89,7 @@ int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, s int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); +int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata); int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); @@ -139,6 +140,9 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); int sd_event_source_get_signal(sd_event_source *s); int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); +int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); +int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); +int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index 67fc595669..b24fd06f01 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -3,9 +3,6 @@ #define foosdid128hfoo /*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index 677ae3b216..259db26330 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -3,10 +3,8 @@ #define foosdipv4acdfoo /*** - This file is part of systemd. - - Copyright (C) 2014 Axis Communications AB. All rights reserved. - Copyright (C) 2015 Tom Gundersen + Copyright © 2014 Axis Communications AB. All rights reserved. + Copyright © 2015 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 diff --git a/src/systemd/src/systemd/sd-ipv4ll.h b/src/systemd/src/systemd/sd-ipv4ll.h index c330b0ae9e..71bd4cfe48 100644 --- a/src/systemd/src/systemd/sd-ipv4ll.h +++ b/src/systemd/src/systemd/sd-ipv4ll.h @@ -3,9 +3,7 @@ #define foosdipv4llfoo /*** - This file is part of systemd. - - Copyright (C) 2014 Axis Communications AB. All rights reserved. + Copyright © 2014 Axis Communications AB. 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 diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h index 0a76fa6314..11a2119ab6 100644 --- a/src/systemd/src/systemd/sd-lldp.h +++ b/src/systemd/src/systemd/sd-lldp.h @@ -3,10 +3,8 @@ #define foosdlldphfoo /*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright © 2014 Tom Gundersen + Copyright © 2014 Susant Sahani 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 diff --git a/src/systemd/src/systemd/sd-ndisc.h b/src/systemd/src/systemd/sd-ndisc.h index 152114507a..6b6249ca03 100644 --- a/src/systemd/src/systemd/sd-ndisc.h +++ b/src/systemd/src/systemd/sd-ndisc.h @@ -3,9 +3,7 @@ #define foosdndiscfoo /*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright © 2014 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 |