diff options
Diffstat (limited to 'src')
76 files changed, 1634 insertions, 1044 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 5f9e21dcba..5505499312 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -1737,7 +1737,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag } else if (r < 0) return r; - r = copy_directory_fd(old_fd, new_path, true); + r = copy_directory_fd(old_fd, new_path, COPY_MERGE|COPY_REFLINK); if (r < 0) goto fallback_fail; diff --git a/src/basic/copy.c b/src/basic/copy.c index e9a7efd232..6273ac9b47 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -45,6 +45,7 @@ #include "strv.h" #include "time-util.h" #include "umask-util.h" +#include "user-util.h" #include "xattr-util.h" #define COPY_BUFFER_SIZE (16*1024u) @@ -68,7 +69,7 @@ static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, return -errno; } -int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { +int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { bool try_cfr = true, try_sendfile = true, try_splice = true; int r; size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ @@ -77,7 +78,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { assert(fdt >= 0); /* Try btrfs reflinks first. */ - if (try_reflink && + if ((copy_flags & COPY_REFLINK) && max_bytes == (uint64_t) -1 && lseek(fdf, 0, SEEK_CUR) == 0 && lseek(fdt, 0, SEEK_CUR) == 0) { @@ -176,7 +177,16 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { return 0; /* return 0 if we hit EOF earlier than the size limit */ } -static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) { +static int fd_copy_symlink( + int df, + const char *from, + const struct stat *st, + int dt, + const char *to, + uid_t override_uid, + gid_t override_gid, + CopyFlags copy_flags) { + _cleanup_free_ char *target = NULL; int r; @@ -191,13 +201,25 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int if (symlinkat(target, dt, to) < 0) return -errno; - if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0) + if (fchownat(dt, to, + uid_is_valid(override_uid) ? override_uid : st->st_uid, + gid_is_valid(override_gid) ? override_gid : st->st_gid, + AT_SYMLINK_NOFOLLOW) < 0) return -errno; return 0; } -static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) { +static int fd_copy_regular( + int df, + const char *from, + const struct stat *st, + int dt, + const char *to, + uid_t override_uid, + gid_t override_gid, + CopyFlags copy_flags) { + _cleanup_close_ int fdf = -1, fdt = -1; struct timespec ts[2]; int r, q; @@ -214,13 +236,15 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int if (fdt < 0) return -errno; - r = copy_bytes(fdf, fdt, (uint64_t) -1, true); + r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); if (r < 0) { unlinkat(dt, to, 0); return r; } - if (fchown(fdt, st->st_uid, st->st_gid) < 0) + if (fchown(fdt, + uid_is_valid(override_uid) ? override_uid : st->st_uid, + gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) r = -errno; if (fchmod(fdt, st->st_mode & 07777) < 0) @@ -229,7 +253,6 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int ts[0] = st->st_atim; ts[1] = st->st_mtim; (void) futimens(fdt, ts); - (void) copy_xattr(fdf, fdt); q = close(fdt); @@ -243,7 +266,15 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int return r; } -static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) { +static int fd_copy_fifo( + int df, + const char *from, + const struct stat *st, + int dt, + const char *to, + uid_t override_uid, + gid_t override_gid, + CopyFlags copy_flags) { int r; assert(from); @@ -254,7 +285,10 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, if (r < 0) return -errno; - if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0) + if (fchownat(dt, to, + uid_is_valid(override_uid) ? override_uid : st->st_uid, + gid_is_valid(override_gid) ? override_gid : st->st_gid, + AT_SYMLINK_NOFOLLOW) < 0) r = -errno; if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) @@ -263,7 +297,15 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, return r; } -static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) { +static int fd_copy_node( + int df, + const char *from, + const struct stat *st, + int dt, + const char *to, + uid_t override_uid, + gid_t override_gid, + CopyFlags copy_flags) { int r; assert(from); @@ -274,7 +316,10 @@ static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, if (r < 0) return -errno; - if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0) + if (fchownat(dt, to, + uid_is_valid(override_uid) ? override_uid : st->st_uid, + gid_is_valid(override_gid) ? override_gid : st->st_gid, + AT_SYMLINK_NOFOLLOW) < 0) r = -errno; if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) @@ -290,7 +335,9 @@ static int fd_copy_directory( int dt, const char *to, dev_t original_device, - bool merge) { + uid_t override_uid, + gid_t override_gid, + CopyFlags copy_flags) { _cleanup_close_ int fdf = -1, fdt = -1; _cleanup_closedir_ DIR *d = NULL; @@ -316,7 +363,7 @@ static int fd_copy_directory( r = mkdirat(dt, to, st->st_mode & 07777); if (r >= 0) created = true; - else if (errno == EEXIST && merge) + else if (errno == EEXIST && (copy_flags & COPY_MERGE)) created = false; else return -errno; @@ -343,19 +390,19 @@ static int fd_copy_directory( continue; if (S_ISREG(buf.st_mode)) - q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name); + q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); else if (S_ISDIR(buf.st_mode)) - q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge); + q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags); else if (S_ISLNK(buf.st_mode)) - q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name); + q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); else if (S_ISFIFO(buf.st_mode)) - q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name); + q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode)) - q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name); + q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); else q = -EOPNOTSUPP; - if (q == -EEXIST && merge) + if (q == -EEXIST && (copy_flags & COPY_MERGE)) q = 0; if (q < 0) @@ -368,7 +415,9 @@ static int fd_copy_directory( st->st_mtim }; - if (fchown(fdt, st->st_uid, st->st_gid) < 0) + if (fchown(fdt, + uid_is_valid(override_uid) ? override_uid : st->st_uid, + gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) r = -errno; if (fchmod(fdt, st->st_mode & 07777) < 0) @@ -381,7 +430,7 @@ static int fd_copy_directory( return r; } -int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) { +int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { struct stat st; assert(from); @@ -391,24 +440,24 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) return -errno; if (S_ISREG(st.st_mode)) - return fd_copy_regular(fdf, from, &st, fdt, to); + return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else if (S_ISDIR(st.st_mode)) - return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge); + return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags); else if (S_ISLNK(st.st_mode)) - return fd_copy_symlink(fdf, from, &st, fdt, to); + return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else if (S_ISFIFO(st.st_mode)) - return fd_copy_fifo(fdf, from, &st, fdt, to); + return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode)) - return fd_copy_node(fdf, from, &st, fdt, to); + return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else return -EOPNOTSUPP; } -int copy_tree(const char *from, const char *to, bool merge) { - return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge); +int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { + return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags); } -int copy_directory_fd(int dirfd, const char *to, bool merge) { +int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) { struct stat st; assert(dirfd >= 0); @@ -420,10 +469,10 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) { if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge); + return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); } -int copy_directory(const char *from, const char *to, bool merge) { +int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { struct stat st; assert(from); @@ -435,10 +484,10 @@ int copy_directory(const char *from, const char *to, bool merge) { if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge); + return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); } -int copy_file_fd(const char *from, int fdt, bool try_reflink) { +int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { _cleanup_close_ int fdf = -1; int r; @@ -449,7 +498,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) { if (fdf < 0) return -errno; - r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink); + r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); (void) copy_times(fdf, fdt); (void) copy_xattr(fdf, fdt); @@ -457,7 +506,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) { return r; } -int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) { +int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { int fdt = -1, r; assert(from); @@ -472,7 +521,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned if (chattr_flags != 0) (void) chattr_fd(fdt, chattr_flags, (unsigned) -1); - r = copy_file_fd(from, fdt, true); + r = copy_file_fd(from, fdt, copy_flags); if (r < 0) { close(fdt); unlink(to); @@ -487,7 +536,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned return 0; } -int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) { +int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { _cleanup_free_ char *t = NULL; int r; @@ -498,11 +547,11 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace if (r < 0) return r; - r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags); + r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags); if (r < 0) return r; - if (replace) { + if (copy_flags & COPY_REPLACE) { r = renameat(AT_FDCWD, t, AT_FDCWD, to); if (r < 0) r = -errno; diff --git a/src/basic/copy.h b/src/basic/copy.h index b5d08ebafe..4f3e11423e 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -24,13 +24,19 @@ #include <stdint.h> #include <sys/types.h> -int copy_file_fd(const char *from, int to, bool try_reflink); -int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags); -int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags); -int copy_tree(const char *from, const char *to, bool merge); -int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge); -int copy_directory_fd(int dirfd, const char *to, bool merge); -int copy_directory(const char *from, const char *to, bool merge); -int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink); +typedef enum CopyFlags { + COPY_REFLINK = 0x1, /* try to reflink */ + COPY_MERGE = 0x2, /* merge existing trees with our new one to copy */ + COPY_REPLACE = 0x4, /* replace an existing file if there's one */ +} CopyFlags; + +int copy_file_fd(const char *from, int to, CopyFlags copy_flags); +int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags); +int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags); +int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags); +int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags); +int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags); +int copy_directory(const char *from, const char *to, CopyFlags copy_flags); +int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags); int copy_times(int fdf, int fdt); int copy_xattr(int fdf, int fdt); diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index e44a357287..a94037b303 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -55,7 +55,7 @@ char* gethostname_malloc(void) { assert_se(uname(&u) >= 0); if (isempty(u.nodename) || streq(u.nodename, "(none)")) - return strdup(u.sysname); + return strdup(FALLBACK_HOSTNAME); return strdup(u.nodename); } diff --git a/src/basic/journal-importer.c b/src/basic/journal-importer.c new file mode 100644 index 0000000000..4c13e46a49 --- /dev/null +++ b/src/basic/journal-importer.c @@ -0,0 +1,481 @@ +/*** + This file is part of systemd. + + Copyright 2014 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <unistd.h> + +#include "alloc-util.h" +#include "journal-importer.h" +#include "fd-util.h" +#include "parse-util.h" +#include "string-util.h" + +enum { + IMPORTER_STATE_LINE = 0, /* waiting to read, or reading line */ + IMPORTER_STATE_DATA_START, /* reading binary data header */ + IMPORTER_STATE_DATA, /* reading binary data */ + IMPORTER_STATE_DATA_FINISH, /* expecting newline */ + IMPORTER_STATE_EOF, /* done */ +}; + +static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { + if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1)) + return log_oom(); + + iovw->iovec[iovw->count++] = (struct iovec) {data, len}; + return 0; +} + +static void iovw_free_contents(struct iovec_wrapper *iovw) { + iovw->iovec = mfree(iovw->iovec); + iovw->size_bytes = iovw->count = 0; +} + +static void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) { + size_t i; + + for (i = 0; i < iovw->count; i++) + iovw->iovec[i].iov_base = (char*) iovw->iovec[i].iov_base - old + new; +} + +size_t iovw_size(struct iovec_wrapper *iovw) { + size_t n = 0, i; + + for (i = 0; i < iovw->count; i++) + n += iovw->iovec[i].iov_len; + + return n; +} + +void journal_importer_cleanup(JournalImporter *imp) { + if (imp->fd >= 0 && !imp->passive_fd) { + log_debug("Closing %s (fd=%d)", imp->name ?: "importer", imp->fd); + safe_close(imp->fd); + } + + free(imp->buf); + iovw_free_contents(&imp->iovw); +} + +static char* realloc_buffer(JournalImporter *imp, size_t size) { + char *b, *old = imp->buf; + + b = GREEDY_REALLOC(imp->buf, imp->size, size); + if (!b) + return NULL; + + iovw_rebase(&imp->iovw, old, imp->buf); + + return b; +} + +static int get_line(JournalImporter *imp, char **line, size_t *size) { + ssize_t n; + char *c = NULL; + + assert(imp); + assert(imp->state == IMPORTER_STATE_LINE); + assert(imp->offset <= imp->filled); + assert(imp->filled <= imp->size); + assert(imp->buf == NULL || imp->size > 0); + assert(imp->fd >= 0); + + for (;;) { + if (imp->buf) { + size_t start = MAX(imp->scanned, imp->offset); + + c = memchr(imp->buf + start, '\n', + imp->filled - start); + if (c != NULL) + break; + } + + imp->scanned = imp->filled; + if (imp->scanned >= DATA_SIZE_MAX) { + log_error("Entry is bigger than %u bytes.", DATA_SIZE_MAX); + return -E2BIG; + } + + if (imp->passive_fd) + /* we have to wait for some data to come to us */ + return -EAGAIN; + + /* We know that imp->filled is at most DATA_SIZE_MAX, so if + we reallocate it, we'll increase the size at least a bit. */ + assert_cc(DATA_SIZE_MAX < ENTRY_SIZE_MAX); + if (imp->size - imp->filled < LINE_CHUNK && + !realloc_buffer(imp, MIN(imp->filled + LINE_CHUNK, ENTRY_SIZE_MAX))) + return log_oom(); + + assert(imp->buf); + assert(imp->size - imp->filled >= LINE_CHUNK || + imp->size == ENTRY_SIZE_MAX); + + n = read(imp->fd, + imp->buf + imp->filled, + imp->size - imp->filled); + if (n < 0) { + if (errno != EAGAIN) + log_error_errno(errno, "read(%d, ..., %zu): %m", + imp->fd, + imp->size - imp->filled); + return -errno; + } else if (n == 0) + return 0; + + imp->filled += n; + } + + *line = imp->buf + imp->offset; + *size = c + 1 - imp->buf - imp->offset; + imp->offset += *size; + + return 1; +} + +static int fill_fixed_size(JournalImporter *imp, void **data, size_t size) { + + assert(imp); + assert(imp->state == IMPORTER_STATE_DATA_START || + imp->state == IMPORTER_STATE_DATA || + imp->state == IMPORTER_STATE_DATA_FINISH); + assert(size <= DATA_SIZE_MAX); + assert(imp->offset <= imp->filled); + assert(imp->filled <= imp->size); + assert(imp->buf != NULL || imp->size == 0); + assert(imp->buf == NULL || imp->size > 0); + assert(imp->fd >= 0); + assert(data); + + while (imp->filled - imp->offset < size) { + int n; + + if (imp->passive_fd) + /* we have to wait for some data to come to us */ + return -EAGAIN; + + if (!realloc_buffer(imp, imp->offset + size)) + return log_oom(); + + n = read(imp->fd, imp->buf + imp->filled, + imp->size - imp->filled); + if (n < 0) { + if (errno != EAGAIN) + log_error_errno(errno, "read(%d, ..., %zu): %m", imp->fd, + imp->size - imp->filled); + return -errno; + } else if (n == 0) + return 0; + + imp->filled += n; + } + + *data = imp->buf + imp->offset; + imp->offset += size; + + return 1; +} + +static int get_data_size(JournalImporter *imp) { + int r; + void *data; + + assert(imp); + assert(imp->state == IMPORTER_STATE_DATA_START); + assert(imp->data_size == 0); + + r = fill_fixed_size(imp, &data, sizeof(uint64_t)); + if (r <= 0) + return r; + + imp->data_size = le64toh( *(uint64_t *) data ); + if (imp->data_size > DATA_SIZE_MAX) { + log_error("Stream declares field with size %zu > DATA_SIZE_MAX = %u", + imp->data_size, DATA_SIZE_MAX); + return -EINVAL; + } + if (imp->data_size == 0) + log_warning("Binary field with zero length"); + + return 1; +} + +static int get_data_data(JournalImporter *imp, void **data) { + int r; + + assert(imp); + assert(data); + assert(imp->state == IMPORTER_STATE_DATA); + + r = fill_fixed_size(imp, data, imp->data_size); + if (r <= 0) + return r; + + return 1; +} + +static int get_data_newline(JournalImporter *imp) { + int r; + char *data; + + assert(imp); + assert(imp->state == IMPORTER_STATE_DATA_FINISH); + + r = fill_fixed_size(imp, (void**) &data, 1); + if (r <= 0) + return r; + + assert(data); + if (*data != '\n') { + log_error("expected newline, got '%c'", *data); + return -EINVAL; + } + + return 1; +} + +static int process_dunder(JournalImporter *imp, char *line, size_t n) { + const char *timestamp; + int r; + + assert(line); + assert(n > 0); + assert(line[n-1] == '\n'); + + /* XXX: is it worth to support timestamps in extended format? + * We don't produce them, but who knows... */ + + timestamp = startswith(line, "__CURSOR="); + if (timestamp) + /* ignore __CURSOR */ + return 1; + + timestamp = startswith(line, "__REALTIME_TIMESTAMP="); + if (timestamp) { + long long unsigned x; + line[n-1] = '\0'; + r = safe_atollu(timestamp, &x); + if (r < 0) + log_warning("Failed to parse __REALTIME_TIMESTAMP: '%s'", timestamp); + else + imp->ts.realtime = x; + return r < 0 ? r : 1; + } + + timestamp = startswith(line, "__MONOTONIC_TIMESTAMP="); + if (timestamp) { + long long unsigned x; + line[n-1] = '\0'; + r = safe_atollu(timestamp, &x); + if (r < 0) + log_warning("Failed to parse __MONOTONIC_TIMESTAMP: '%s'", timestamp); + else + imp->ts.monotonic = x; + return r < 0 ? r : 1; + } + + timestamp = startswith(line, "__"); + if (timestamp) { + log_notice("Unknown dunder line %s", line); + return 1; + } + + /* no dunder */ + return 0; +} + +int journal_importer_process_data(JournalImporter *imp) { + int r; + + switch(imp->state) { + case IMPORTER_STATE_LINE: { + char *line, *sep; + size_t n = 0; + + assert(imp->data_size == 0); + + r = get_line(imp, &line, &n); + if (r < 0) + return r; + if (r == 0) { + imp->state = IMPORTER_STATE_EOF; + return r; + } + assert(n > 0); + assert(line[n-1] == '\n'); + + if (n == 1) { + log_trace("Received empty line, event is ready"); + return 1; + } + + r = process_dunder(imp, line, n); + if (r != 0) + return r < 0 ? r : 0; + + /* MESSAGE=xxx\n + or + COREDUMP\n + LLLLLLLL0011223344...\n + */ + sep = memchr(line, '=', n); + if (sep) { + /* chomp newline */ + n--; + + r = iovw_put(&imp->iovw, line, n); + if (r < 0) + return r; + } else { + /* replace \n with = */ + line[n-1] = '='; + + imp->field_len = n; + imp->state = IMPORTER_STATE_DATA_START; + + /* we cannot put the field in iovec until we have all data */ + } + + log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary"); + + return 0; /* continue */ + } + + case IMPORTER_STATE_DATA_START: + assert(imp->data_size == 0); + + r = get_data_size(imp); + // log_debug("get_data_size() -> %d", r); + if (r < 0) + return r; + if (r == 0) { + imp->state = IMPORTER_STATE_EOF; + return 0; + } + + imp->state = imp->data_size > 0 ? + IMPORTER_STATE_DATA : IMPORTER_STATE_DATA_FINISH; + + return 0; /* continue */ + + case IMPORTER_STATE_DATA: { + void *data; + char *field; + + assert(imp->data_size > 0); + + r = get_data_data(imp, &data); + // log_debug("get_data_data() -> %d", r); + if (r < 0) + return r; + if (r == 0) { + imp->state = IMPORTER_STATE_EOF; + return 0; + } + + assert(data); + + field = (char*) data - sizeof(uint64_t) - imp->field_len; + memmove(field + sizeof(uint64_t), field, imp->field_len); + + r = iovw_put(&imp->iovw, field + sizeof(uint64_t), imp->field_len + imp->data_size); + if (r < 0) + return r; + + imp->state = IMPORTER_STATE_DATA_FINISH; + + return 0; /* continue */ + } + + case IMPORTER_STATE_DATA_FINISH: + r = get_data_newline(imp); + // log_debug("get_data_newline() -> %d", r); + if (r < 0) + return r; + if (r == 0) { + imp->state = IMPORTER_STATE_EOF; + return 0; + } + + imp->data_size = 0; + imp->state = IMPORTER_STATE_LINE; + + return 0; /* continue */ + default: + assert_not_reached("wtf?"); + } +} + +int journal_importer_push_data(JournalImporter *imp, const char *data, size_t size) { + assert(imp); + assert(imp->state != IMPORTER_STATE_EOF); + + if (!realloc_buffer(imp, imp->filled + size)) { + log_error("Failed to store received data of size %zu " + "(in addition to existing %zu bytes with %zu filled): %s", + size, imp->size, imp->filled, strerror(ENOMEM)); + return -ENOMEM; + } + + memcpy(imp->buf + imp->filled, data, size); + imp->filled += size; + + return 0; +} + +void journal_importer_drop_iovw(JournalImporter *imp) { + size_t remain, target; + + /* This function drops processed data that along with the iovw that points at it */ + + iovw_free_contents(&imp->iovw); + + /* possibly reset buffer position */ + remain = imp->filled - imp->offset; + + if (remain == 0) /* no brainer */ + imp->offset = imp->scanned = imp->filled = 0; + else if (imp->offset > imp->size - imp->filled && + imp->offset > remain) { + memcpy(imp->buf, imp->buf + imp->offset, remain); + imp->offset = imp->scanned = 0; + imp->filled = remain; + } + + target = imp->size; + while (target > 16 * LINE_CHUNK && imp->filled < target / 2) + target /= 2; + if (target < imp->size) { + char *tmp; + + tmp = realloc(imp->buf, target); + if (!tmp) + log_warning("Failed to reallocate buffer to (smaller) size %zu", + target); + else { + log_debug("Reallocated buffer from %zu to %zu bytes", + imp->size, target); + imp->buf = tmp; + imp->size = target; + } + } +} + +bool journal_importer_eof(const JournalImporter *imp) { + return imp->state == IMPORTER_STATE_EOF; +} diff --git a/src/basic/journal-importer.h b/src/basic/journal-importer.h new file mode 100644 index 0000000000..b3e308dd6d --- /dev/null +++ b/src/basic/journal-importer.h @@ -0,0 +1,70 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#pragma once + +#include <stddef.h> +#include <stdbool.h> +#include <sys/uio.h> + +#include "time-util.h" + +/* Make sure not to make this smaller than the maximum coredump size. + * See COREDUMP_MAX in coredump.c */ +#define ENTRY_SIZE_MAX (1024*1024*770u) +#define DATA_SIZE_MAX (1024*1024*768u) +#define LINE_CHUNK 8*1024u + +struct iovec_wrapper { + struct iovec *iovec; + size_t size_bytes; + size_t count; +}; + +size_t iovw_size(struct iovec_wrapper *iovw); + +typedef struct JournalImporter { + int fd; + bool passive_fd; + char *name; + + char *buf; + size_t size; /* total size of the buffer */ + size_t offset; /* offset to the beginning of live data in the buffer */ + size_t scanned; /* number of bytes since the beginning of data without a newline */ + size_t filled; /* total number of bytes in the buffer */ + + size_t field_len; /* used for binary fields: the field name length */ + size_t data_size; /* and the size of the binary data chunk being processed */ + + struct iovec_wrapper iovw; + + int state; + dual_timestamp ts; +} JournalImporter; + +void journal_importer_cleanup(JournalImporter *); +int journal_importer_process_data(JournalImporter *); +int journal_importer_push_data(JournalImporter *, const char *data, size_t size); +void journal_importer_drop_iovw(JournalImporter *); +bool journal_importer_eof(const JournalImporter *); + +static inline size_t journal_importer_bytes_remaining(const JournalImporter *imp) { + return imp->filled; +} diff --git a/src/basic/log.c b/src/basic/log.c index 1362b1c086..e6d2d61d72 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -1164,7 +1164,7 @@ int log_syntax_internal( return log_struct_internal( level, error, file, line, func, - LOG_MESSAGE_ID(SD_MESSAGE_INVALID_CONFIGURATION), + "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, "CONFIG_FILE=%s", config_file, "CONFIG_LINE=%u", config_line, LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer), diff --git a/src/basic/log.h b/src/basic/log.h index 2afee20bb5..9cacbb6b70 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -214,9 +214,8 @@ bool log_on_console(void) _pure_; const char *log_target_to_string(LogTarget target) _const_; LogTarget log_target_from_string(const char *s) _pure_; -/* Helpers to prepare various fields for structured logging */ +/* Helper to prepare various field for structured logging */ #define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ -#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x) void log_received_signal(int level, const struct signalfd_siginfo *si); diff --git a/src/basic/virt.c b/src/basic/virt.c index 830dc655e3..9d615da681 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -329,8 +329,10 @@ int detect_vm(void) { * -> Third try to detect from dmi. */ dmi = detect_vm_dmi(); - if (dmi == VIRTUALIZATION_ORACLE) - return dmi; + if (dmi == VIRTUALIZATION_ORACLE) { + r = dmi; + goto finish; + } r = detect_vm_cpuid(); if (r < 0) diff --git a/src/core/execute.c b/src/core/execute.c index 4c2968f971..f455afa962 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2981,7 +2981,7 @@ int exec_spawn(Unit *unit, log_open(); if (error_message) log_struct_errno(LOG_ERR, r, - LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED), + "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR, LOG_UNIT_ID(unit), LOG_UNIT_MESSAGE(unit, "%s: %m", error_message), @@ -2989,7 +2989,7 @@ int exec_spawn(Unit *unit, NULL); else log_struct_errno(LOG_ERR, r, - LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED), + "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR, LOG_UNIT_ID(unit), LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m", exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD), diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index 68be52856b..845e31e1c5 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -31,10 +31,10 @@ #include "util.h" int hostname_setup(void) { - int r; _cleanup_free_ char *b = NULL; - const char *hn; bool enoent = false; + const char *hn; + int r; r = read_hostname_config("/etc/hostname", &b); if (r < 0) { @@ -56,7 +56,7 @@ int hostname_setup(void) { if (enoent) log_info("No hostname configured."); - hn = "localhost"; + hn = FALLBACK_HOSTNAME; } r = sethostname_idempotent(hn); diff --git a/src/core/job.c b/src/core/job.c index 07f4b74c5c..e2349830a8 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -746,9 +746,8 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { } static void job_log_status_message(Unit *u, JobType t, JobResult result) { - const char *format; + const char *format, *mid; char buf[LINE_MAX]; - sd_id128_t mid; static const int job_result_log_level[_JOB_RESULT_MAX] = { [JOB_DONE] = LOG_INFO, [JOB_CANCELED] = LOG_INFO, @@ -784,16 +783,19 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { switch (t) { case JOB_START: - mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED; + if (result == JOB_DONE) + mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR; + else + mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_FAILED_STR; break; case JOB_RELOAD: - mid = SD_MESSAGE_UNIT_RELOADED; + mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADED_STR; break; case JOB_STOP: case JOB_RESTART: - mid = SD_MESSAGE_UNIT_STOPPED; + mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPED_STR; break; default: @@ -806,7 +808,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { } log_struct(job_result_log_level[result], - LOG_MESSAGE_ID(mid), + mid, LOG_UNIT_ID(u), LOG_MESSAGE("%s", buf), "RESULT=%s", job_result_to_string(result), diff --git a/src/core/manager.c b/src/core/manager.c index 5646889a8e..b509adfc64 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2171,7 +2171,7 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint assert(m->time_change_fd == fd); log_struct(LOG_DEBUG, - LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), + "MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR, LOG_MESSAGE("Time has been changed"), NULL); @@ -2930,7 +2930,7 @@ static void manager_notify_finished(Manager *m) { initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic; log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), + "MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR, "KERNEL_USEC="USEC_FMT, kernel_usec, "INITRD_USEC="USEC_FMT, initrd_usec, "USERSPACE_USEC="USEC_FMT, userspace_usec, @@ -2945,7 +2945,7 @@ static void manager_notify_finished(Manager *m) { initrd_usec = 0; log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), + "MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR, "KERNEL_USEC="USEC_FMT, kernel_usec, "USERSPACE_USEC="USEC_FMT, userspace_usec, LOG_MESSAGE("Startup finished in %s (kernel) + %s (userspace) = %s.", @@ -2959,7 +2959,7 @@ static void manager_notify_finished(Manager *m) { total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic; log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_USER_STARTUP_FINISHED), + "MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR, "USERSPACE_USEC="USEC_FMT, userspace_usec, LOG_MESSAGE("Startup finished in %s.", format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)), diff --git a/src/core/socket.c b/src/core/socket.c index a7b9ada65c..84b7a1a82d 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1340,11 +1340,11 @@ static int usbffs_write_descs(int fd, Service *s) { if (!s->usb_function_descriptors || !s->usb_function_strings) return -EINVAL; - r = copy_file_fd(s->usb_function_descriptors, fd, false); + r = copy_file_fd(s->usb_function_descriptors, fd, 0); if (r < 0) return r; - return copy_file_fd(s->usb_function_strings, fd, false); + return copy_file_fd(s->usb_function_strings, fd, 0); } static int usbffs_select_ep(const struct dirent *d) { diff --git a/src/core/unit.c b/src/core/unit.c index 0b680e9544..bb05d2abfb 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1466,9 +1466,8 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) { } static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { - const char *format; + const char *format, *mid; char buf[LINE_MAX]; - sd_id128_t mid; assert(u); @@ -1486,9 +1485,9 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { snprintf(buf, sizeof buf, format, unit_description(u)); REENABLE_WARNING; - mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING : - t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING : - SD_MESSAGE_UNIT_RELOADING; + mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR : + t == JOB_STOP ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPING_STR : + "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADING_STR; /* Note that we deliberately use LOG_MESSAGE() instead of * LOG_UNIT_MESSAGE() here, since this is supposed to mimic @@ -1497,7 +1496,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { * possible, which means we should avoid the low-level unit * name. */ log_struct(LOG_INFO, - LOG_MESSAGE_ID(mid), + mid, LOG_UNIT_ID(u), LOG_MESSAGE("%s", buf), NULL); @@ -4069,7 +4068,7 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) { } log_struct(LOG_NOTICE, - LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING), + "MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR, LOG_UNIT_ID(u), LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where), "WHERE=%s", where, @@ -4091,7 +4090,7 @@ int unit_fail_if_symlink(Unit *u, const char* where) { return 0; log_struct(LOG_ERR, - LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING), + "MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR, LOG_UNIT_ID(u), LOG_UNIT_MESSAGE(u, "Mount on symlink %s not allowed.", where), "WHERE=%s", where, diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 1f6fb5de1e..d76d49a679 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -47,7 +47,7 @@ #include "fileio.h" #include "fs-util.h" #include "io-util.h" -#include "journald-native.h" +#include "journal-importer.h" #include "log.h" #include "macro.h" #include "missing.h" @@ -352,7 +352,7 @@ static int save_external_coredump( if (fd < 0) return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn); - r = copy_bytes(input_fd, fd, max_size, false); + r = copy_bytes(input_fd, fd, max_size, 0); if (r < 0) { log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]); goto fail; @@ -360,7 +360,7 @@ static int save_external_coredump( log_struct(LOG_INFO, LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size), "SIZE_LIMIT=%zu", max_size, - LOG_MESSAGE_ID(SD_MESSAGE_TRUNCATED_CORE), + "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR, NULL); if (fstat(fd, &st) < 0) { @@ -820,7 +820,7 @@ static void map_context_fields(const struct iovec *iovec, const char *context[]) static int process_socket(int fd) { _cleanup_close_ int coredump_fd = -1; struct iovec *iovec = NULL; - size_t n_iovec = 0, n_iovec_allocated = 0, i; + size_t n_iovec = 0, n_allocated = 0, i; const char *context[_CONTEXT_MAX] = {}; int r; @@ -830,6 +830,8 @@ static int process_socket(int fd) { log_parse_environment(); log_open(); + log_debug("Processing coredump received on stdin..."); + for (;;) { union { struct cmsghdr cmsghdr; @@ -843,7 +845,7 @@ static int process_socket(int fd) { ssize_t n; ssize_t l; - if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) { + if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + 3)) { r = log_oom(); goto finish; } @@ -907,7 +909,7 @@ static int process_socket(int fd) { n_iovec++; } - if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) { + if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + 3)) { r = log_oom(); goto finish; } @@ -922,7 +924,7 @@ static int process_socket(int fd) { assert(context[CONTEXT_COMM]); assert(coredump_fd >= 0); - r = submit_coredump(context, iovec, n_iovec_allocated, n_iovec, coredump_fd); + r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd); finish: for (i = 0; i < n_iovec; i++) @@ -1025,45 +1027,47 @@ static int process_special_crash(const char *context[], int input_fd) { return 0; } -static int process_kernel(int argc, char* argv[]) { +static char* set_iovec_field(struct iovec iovec[27], size_t *n_iovec, const char *field, const char *value) { + char *x; + + x = strappend(field, value); + if (x) + IOVEC_SET_STRING(iovec[(*n_iovec)++], x); + return x; +} - /* The small core field we allocate on the stack, to keep things simple */ - char - *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, - *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, - *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, - *core_user_unit = NULL, *core_slice = NULL, *core_timestamp = NULL, *core_rlimit = NULL; +static char* set_iovec_field_free(struct iovec iovec[27], size_t *n_iovec, const char *field, char *value) { + char *x; - /* The larger ones we allocate on the heap */ - _cleanup_free_ char - *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, - *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL, - *core_proc_mountinfo = NULL, *core_container_cmdline = NULL; + x = set_iovec_field(iovec, n_iovec, field, value); + free(value); + return x; +} + +static int gather_pid_metadata( + const char *context[_CONTEXT_MAX], + char **comm_fallback, + char **comm_ret, + struct iovec *iovec, size_t *n_iovec) { + /* We need 25 empty slots in iovec! + * Note that if we fail on oom later on, we do not roll-back changes to the iovec + * structure. (It remains valid, with the first n_iovec fields initialized.) */ _cleanup_free_ char *exe = NULL, *comm = NULL; - const char *context[_CONTEXT_MAX]; - bool proc_self_root_is_slash; - struct iovec iovec[27]; - size_t n_iovec = 0; uid_t owner_uid; - const char *p; pid_t pid; char *t; + const char *p; int r; - if (argc < CONTEXT_COMM + 1) { - log_error("Not enough arguments passed from kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1); - return -EINVAL; - } - - r = parse_pid(argv[CONTEXT_PID + 1], &pid); + r = parse_pid(context[CONTEXT_PID], &pid); if (r < 0) - return log_error_errno(r, "Failed to parse PID."); + return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]); r = get_process_comm(pid, &comm); if (r < 0) { log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m"); - comm = strv_join(argv + CONTEXT_COMM + 1, " "); + comm = strv_join(comm_fallback, " "); if (!comm) return log_oom(); } @@ -1072,15 +1076,6 @@ static int process_kernel(int argc, char* argv[]) { if (r < 0) log_warning_errno(r, "Failed to get EXE, ignoring: %m"); - context[CONTEXT_PID] = argv[CONTEXT_PID + 1]; - context[CONTEXT_UID] = argv[CONTEXT_UID + 1]; - context[CONTEXT_GID] = argv[CONTEXT_GID + 1]; - context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 1]; - context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 1]; - context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 1]; - context[CONTEXT_COMM] = comm; - context[CONTEXT_EXE] = exe; - if (cg_pid_get_unit(pid, &t) >= 0) { /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */ @@ -1096,186 +1091,238 @@ static int process_kernel(int argc, char* argv[]) { return process_special_crash(context, STDIN_FILENO); } - core_unit = strjoina("COREDUMP_UNIT=", t); - free(t); - - IOVEC_SET_STRING(iovec[n_iovec++], core_unit); + set_iovec_field_free(iovec, n_iovec, "COREDUMP_UNIT=", t); } /* OK, now we know it's not the journal, hence we can make use of it now. */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); - if (cg_pid_get_user_unit(pid, &t) >= 0) { - core_user_unit = strjoina("COREDUMP_USER_UNIT=", t); - free(t); + if (cg_pid_get_user_unit(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t); - IOVEC_SET_STRING(iovec[n_iovec++], core_user_unit); - } + /* The next few are mandatory */ + if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) + return log_oom(); - core_pid = strjoina("COREDUMP_PID=", context[CONTEXT_PID]); - IOVEC_SET_STRING(iovec[n_iovec++], core_pid); + if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) + return log_oom(); - core_uid = strjoina("COREDUMP_UID=", context[CONTEXT_UID]); - IOVEC_SET_STRING(iovec[n_iovec++], core_uid); + if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) + return log_oom(); - core_gid = strjoina("COREDUMP_GID=", context[CONTEXT_GID]); - IOVEC_SET_STRING(iovec[n_iovec++], core_gid); + if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) + return log_oom(); - core_signal = strjoina("COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]); - IOVEC_SET_STRING(iovec[n_iovec++], core_signal); + if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) + return log_oom(); - core_rlimit = strjoina("COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]); - IOVEC_SET_STRING(iovec[n_iovec++], core_rlimit); + if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", comm)) + return log_oom(); - if (sd_pid_get_session(pid, &t) >= 0) { - core_session = strjoina("COREDUMP_SESSION=", t); - free(t); + if (exe && + !set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", exe)) + return log_oom(); - IOVEC_SET_STRING(iovec[n_iovec++], core_session); - } + if (sd_pid_get_session(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_SESSION=", t); if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { - r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); + r = asprintf(&t, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); if (r > 0) - IOVEC_SET_STRING(iovec[n_iovec++], core_owner_uid); + IOVEC_SET_STRING(iovec[(*n_iovec)++], t); } - if (sd_pid_get_slice(pid, &t) >= 0) { - core_slice = strjoina("COREDUMP_SLICE=", t); - free(t); + if (sd_pid_get_slice(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_SLICE=", t); - IOVEC_SET_STRING(iovec[n_iovec++], core_slice); - } + if (get_process_cmdline(pid, 0, false, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_CMDLINE=", t); - if (comm) { - core_comm = strjoina("COREDUMP_COMM=", comm); - IOVEC_SET_STRING(iovec[n_iovec++], core_comm); - } + if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_CGROUP=", t); - if (exe) { - core_exe = strjoina("COREDUMP_EXE=", exe); - IOVEC_SET_STRING(iovec[n_iovec++], core_exe); - } + if (compose_open_fds(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_OPEN_FDS=", t); - if (get_process_cmdline(pid, 0, false, &t) >= 0) { - core_cmdline = strjoina("COREDUMP_CMDLINE=", t); - free(t); + p = procfs_file_alloca(pid, "status"); + if (read_full_file(p, &t, NULL) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_STATUS=", t); - IOVEC_SET_STRING(iovec[n_iovec++], core_cmdline); - } + p = procfs_file_alloca(pid, "maps"); + if (read_full_file(p, &t, NULL) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MAPS=", t); - if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { - core_cgroup = strjoina("COREDUMP_CGROUP=", t); - free(t); + p = procfs_file_alloca(pid, "limits"); + if (read_full_file(p, &t, NULL) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_LIMITS=", t); - IOVEC_SET_STRING(iovec[n_iovec++], core_cgroup); - } + p = procfs_file_alloca(pid, "cgroup"); + if (read_full_file(p, &t, NULL) >=0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_CGROUP=", t); - if (compose_open_fds(pid, &t) >= 0) { - core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); - free(t); + p = procfs_file_alloca(pid, "mountinfo"); + if (read_full_file(p, &t, NULL) >=0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t); - if (core_open_fds) - IOVEC_SET_STRING(iovec[n_iovec++], core_open_fds); - } + if (get_process_cwd(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t); - p = procfs_file_alloca(pid, "status"); - if (read_full_file(p, &t, NULL) >= 0) { - core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); - free(t); + if (get_process_root(pid, &t) >= 0) { + bool proc_self_root_is_slash; - if (core_proc_status) - IOVEC_SET_STRING(iovec[n_iovec++], core_proc_status); - } + proc_self_root_is_slash = strcmp(t, "/") == 0; - p = procfs_file_alloca(pid, "maps"); - if (read_full_file(p, &t, NULL) >= 0) { - core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); - free(t); + set_iovec_field_free(iovec, n_iovec, "COREDUMP_ROOT=", t); - if (core_proc_maps) - IOVEC_SET_STRING(iovec[n_iovec++], core_proc_maps); + /* If the process' root is "/", then there is a chance it has + * mounted own root and hence being containerized. */ + if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_CONTAINER_CMDLINE=", t); } - p = procfs_file_alloca(pid, "limits"); - if (read_full_file(p, &t, NULL) >= 0) { - core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); - free(t); + if (get_process_environ(pid, &t) >= 0) + set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t); - if (core_proc_limits) - IOVEC_SET_STRING(iovec[n_iovec++], core_proc_limits); + t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL); + if (t) + IOVEC_SET_STRING(iovec[(*n_iovec)++], t); + + if (comm_ret) { + *comm_ret = comm; + comm = NULL; } - p = procfs_file_alloca(pid, "cgroup"); - if (read_full_file(p, &t, NULL) >=0) { - core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); - free(t); + return 0; +} - if (core_proc_cgroup) - IOVEC_SET_STRING(iovec[n_iovec++], core_proc_cgroup); - } +static int process_kernel(int argc, char* argv[]) { - p = procfs_file_alloca(pid, "mountinfo"); - if (read_full_file(p, &t, NULL) >=0) { - core_proc_mountinfo = strappend("COREDUMP_PROC_MOUNTINFO=", t); - free(t); + const char *context[_CONTEXT_MAX]; + struct iovec iovec[27]; + size_t i, n_iovec, n_to_free = 0; + int r; + + log_debug("Processing coredump received from the kernel..."); - if (core_proc_mountinfo) - IOVEC_SET_STRING(iovec[n_iovec++], core_proc_mountinfo); + if (argc < CONTEXT_COMM + 1) { + log_error("Not enough arguments passed by the kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1); + return -EINVAL; } - if (get_process_cwd(pid, &t) >= 0) { - core_cwd = strjoina("COREDUMP_CWD=", t); - free(t); + context[CONTEXT_PID] = argv[CONTEXT_PID + 1]; + context[CONTEXT_UID] = argv[CONTEXT_UID + 1]; + context[CONTEXT_GID] = argv[CONTEXT_GID + 1]; + context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 1]; + context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 1]; + context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 1]; - IOVEC_SET_STRING(iovec[n_iovec++], core_cwd); - } + r = gather_pid_metadata(context, argv + CONTEXT_COMM + 1, NULL, iovec, &n_to_free); + if (r < 0) + goto finish; + n_iovec = n_to_free; - if (get_process_root(pid, &t) >= 0) { - core_root = strjoina("COREDUMP_ROOT=", t); + IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR); - IOVEC_SET_STRING(iovec[n_iovec++], core_root); + assert_cc(2 == LOG_CRIT); + IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2"); - /* If the process' root is "/", then there is a chance it has - * mounted own root and hence being containerized. */ - proc_self_root_is_slash = strcmp(t, "/") == 0; - free(t); - if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0) { - core_container_cmdline = strappend("COREDUMP_CONTAINER_CMDLINE=", t); - free(t); + assert(n_iovec <= ELEMENTSOF(iovec)); - if (core_container_cmdline) - IOVEC_SET_STRING(iovec[n_iovec++], core_container_cmdline); - } + r = send_iovec(iovec, n_iovec, STDIN_FILENO); + + finish: + for (i = 0; i < n_to_free; i++) + free(iovec[i].iov_base); + + return r; +} + +static int process_backtrace(int argc, char *argv[]) { + const char *context[_CONTEXT_MAX]; + _cleanup_free_ char *comm = NULL, *message = NULL; + _cleanup_free_ struct iovec *iovec = NULL; + size_t n_iovec, n_allocated, n_to_free = 0, i; + int r; + JournalImporter importer = { + .fd = STDIN_FILENO, + }; + + log_debug("Processing backtrace on stdin..."); + + if (argc < CONTEXT_COMM + 1) { + log_error("Not enough arguments passed (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1); + return -EINVAL; } - if (get_process_environ(pid, &t) >= 0) { - core_environ = strappend("COREDUMP_ENVIRON=", t); - free(t); + context[CONTEXT_PID] = argv[CONTEXT_PID + 2]; + context[CONTEXT_UID] = argv[CONTEXT_UID + 2]; + context[CONTEXT_GID] = argv[CONTEXT_GID + 2]; + context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 2]; + context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 2]; + context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 2]; + + n_allocated = 32; /* 25 metadata, 2 static, +unknown input, rounded up */ + iovec = new(struct iovec, n_allocated); + if (!iovec) + return log_oom(); - if (core_environ) - IOVEC_SET_STRING(iovec[n_iovec++], core_environ); + r = gather_pid_metadata(context, argv + CONTEXT_COMM + 2, &comm, iovec, &n_to_free); + if (r < 0) + goto finish; + n_iovec = n_to_free; + + while (true) { + r = journal_importer_process_data(&importer); + if (r < 0) { + log_error_errno(r, "Failed to parse journal entry on stdin: %m"); + goto finish; + } + if (r == 1) + break; } - core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000"); - IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp); + if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + importer.iovw.count + 2)) + return log_oom(); - IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); + if (journal_importer_eof(&importer)) { + log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter"); + message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], " (", comm, ")" + " of user ", context[CONTEXT_UID], + " failed with ", context[CONTEXT_SIGNAL]); + if (!message) { + r = log_oom(); + goto finish; + } + IOVEC_SET_STRING(iovec[n_iovec++], message); + } else { + for (i = 0; i < importer.iovw.count; i++) + iovec[n_iovec++] = importer.iovw.iovec[i]; + } + + IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR); assert_cc(2 == LOG_CRIT); IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2"); - assert(n_iovec <= ELEMENTSOF(iovec)); + assert(n_iovec <= n_allocated); + + r = sd_journal_sendv(iovec, n_iovec); + if (r < 0) + log_error_errno(r, "Failed to log backtrace: %m"); - return send_iovec(iovec, n_iovec, STDIN_FILENO); + finish: + for (i = 0; i < n_to_free; i++) + free(iovec[i].iov_base); + + return r; } int main(int argc, char *argv[]) { int r; - /* First, log to a safe place, since we don't know what crashed and it might be journald which we'd rather not - * log to then. */ + /* First, log to a safe place, since we don't know what crashed and it might + * be journald which we'd rather not log to then. */ log_set_target(LOG_TARGET_KMSG); log_open(); @@ -1295,11 +1342,14 @@ int main(int argc, char *argv[]) { goto finish; } - /* If we got an fd passed, we are running in coredumpd mode. Otherwise we are invoked from the kernel as - * coredump handler */ - if (r == 0) - r = process_kernel(argc, argv); - else if (r == 1) + /* If we got an fd passed, we are running in coredumpd mode. Otherwise we + * are invoked from the kernel as coredump handler. */ + if (r == 0) { + if (streq_ptr(argv[1], "--backtrace")) + r = process_backtrace(argc, argv); + else + r = process_kernel(argc, argv); + } else if (r == 1) r = process_socket(SD_LISTEN_FDS_START); else { log_error("Received unexpected number of file descriptors."); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index fcb741b353..6abd99430b 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -25,6 +25,7 @@ #include <unistd.h> #include "sd-journal.h" +#include "sd-messages.h" #include "alloc-util.h" #include "compress.h" @@ -38,10 +39,10 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" -#include "set.h" #include "sigbus.h" #include "signal-util.h" #include "string-util.h" +#include "strv.h" #include "terminal-util.h" #include "user-util.h" #include "util.h" @@ -60,36 +61,9 @@ static int arg_no_legend = false; static int arg_one = false; static FILE* arg_output = NULL; static bool arg_reverse = false; +static char** arg_matches = NULL; -static Set *new_matches(void) { - Set *set; - char *tmp; - int r; - - set = set_new(NULL); - if (!set) { - log_oom(); - return NULL; - } - - tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); - if (!tmp) { - log_oom(); - set_free(set); - return NULL; - } - - r = set_consume(set, tmp); - if (r < 0) { - log_error_errno(r, "failed to add to set: %m"); - set_free(set); - return NULL; - } - - return set; -} - -static int add_match(Set *set, const char *match) { +static int add_match(sd_journal *j, const char *match) { _cleanup_free_ char *p = NULL; char *pattern = NULL; const char* prefix; @@ -101,7 +75,8 @@ static int add_match(Set *set, const char *match) { else if (strchr(match, '/')) { r = path_make_absolute_cwd(match, &p); if (r < 0) - goto fail; + return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match); + match = p; prefix = "COREDUMP_EXE="; } else if (parse_pid(match, &pid) >= 0) @@ -110,19 +85,35 @@ static int add_match(Set *set, const char *match) { prefix = "COREDUMP_COMM="; pattern = strjoin(prefix, match); - if (!pattern) { - r = -ENOMEM; - goto fail; - } + if (!pattern) + return log_oom(); + + log_debug("Adding match: %s", pattern); + r = sd_journal_add_match(j, pattern, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match \"%s\": %m", match); + return 0; +} + +static int add_matches(sd_journal *j) { + char **match; + int r; - log_debug("Adding pattern: %s", pattern); - r = set_consume(set, pattern); + r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR); + + r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR); + + STRV_FOREACH(match, arg_matches) { + r = add_match(j, *match); + if (r < 0) + return r; + } return 0; -fail: - return log_error_errno(r, "Failed to add match: %m"); } static void help(void) { @@ -147,14 +138,14 @@ static void help(void) { , program_invocation_short_name); } -static int parse_argv(int argc, char *argv[], Set *matches) { +static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_NO_PAGER, ARG_NO_LEGEND, }; - int r, c; + int c; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, @@ -251,12 +242,8 @@ static int parse_argv(int argc, char *argv[], Set *matches) { return -EINVAL; } - while (optind < argc) { - r = add_match(matches, argv[optind]); - if (r != 0) - return r; - optind++; - } + if (optind < argc) + arg_matches = argv + optind; return 0; } @@ -329,7 +316,7 @@ static int print_field(FILE* file, sd_journal *j) { static int print_list(FILE* file, sd_journal *j, int had_legend) { _cleanup_free_ char - *pid = NULL, *uid = NULL, *gid = NULL, + *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL, *filename = NULL, *coredump = NULL; const void *d; @@ -338,11 +325,13 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { char buf[FORMAT_TIMESTAMP_MAX]; int r; const char *present; + bool normal_coredump; assert(file); assert(j); SD_JOURNAL_FOREACH_DATA(j, d, l) { + RETRIEVE(d, l, "MESSAGE_ID", mid); RETRIEVE(d, l, "COREDUMP_PID", pid); RETRIEVE(d, l, "COREDUMP_UID", uid); RETRIEVE(d, l, "COREDUMP_GID", gid); @@ -375,6 +364,8 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { 8, "COREFILE", "EXE"); + normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR); + if (filename) if (access(filename, R_OK) == 0) present = "present"; @@ -384,15 +375,17 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { present = "error"; else if (coredump) present = "journal"; - else + else if (normal_coredump) present = "none"; + else + present = "-"; fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n", FORMAT_TIMESTAMP_WIDTH, buf, 6, strna(pid), 5, strna(uid), 5, strna(gid), - 3, strna(sgnl), + 3, normal_coredump ? strna(sgnl) : "-", 8, present, strna(exe ?: (comm ?: cmdline))); @@ -401,7 +394,7 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { static int print_info(FILE *file, sd_journal *j, bool need_space) { _cleanup_free_ char - *pid = NULL, *uid = NULL, *gid = NULL, + *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL, *unit = NULL, *user_unit = NULL, *session = NULL, *boot_id = NULL, *machine_id = NULL, *hostname = NULL, @@ -410,12 +403,14 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { *coredump = NULL; const void *d; size_t l; + bool normal_coredump; int r; assert(file); assert(j); SD_JOURNAL_FOREACH_DATA(j, d, l) { + RETRIEVE(d, l, "MESSAGE_ID", mid); RETRIEVE(d, l, "COREDUMP_PID", pid); RETRIEVE(d, l, "COREDUMP_UID", uid); RETRIEVE(d, l, "COREDUMP_GID", gid); @@ -441,6 +436,8 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { if (need_space) fputs("\n", file); + normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR); + if (comm) fprintf(file, " PID: %s%s%s (%s)\n", @@ -486,11 +483,12 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { if (sgnl) { int sig; + const char *name = normal_coredump ? "Signal" : "Reason"; - if (safe_atoi(sgnl, &sig) >= 0) - fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig)); + if (normal_coredump && safe_atoi(sgnl, &sig) >= 0) + fprintf(file, " %s: %s (%s)\n", name, sgnl, signal_to_string(sig)); else - fprintf(file, " Signal: %s\n", sgnl); + fprintf(file, " %s: %s\n", name, sgnl); } if (timestamp) { @@ -875,22 +873,13 @@ finish: int main(int argc, char *argv[]) { _cleanup_(sd_journal_closep) sd_journal*j = NULL; - const char* match; - Iterator it; int r = 0; - _cleanup_set_free_free_ Set *matches = NULL; setlocale(LC_ALL, ""); log_parse_environment(); log_open(); - matches = new_matches(); - if (!matches) { - r = -ENOMEM; - goto end; - } - - r = parse_argv(argc, argv, matches); + r = parse_argv(argc, argv); if (r < 0) goto end; @@ -913,14 +902,9 @@ int main(int argc, char *argv[]) { } } - SET_FOREACH(match, matches, it) { - r = sd_journal_add_match(j, match, strlen(match)); - if (r != 0) { - log_error_errno(r, "Failed to add match '%s': %m", - match); - goto end; - } - } + r = add_matches(j); + if (r < 0) + goto end; if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { _cleanup_free_ char *filter; diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index fd7051f21e..bc16290c72 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -252,7 +252,7 @@ static int process_locale(void) { if (arg_copy_locale && arg_root) { mkdir_parents(etc_localeconf, 0755); - r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0); + r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, COPY_REFLINK); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf); diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index ef7fb6ac42..60a769e944 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -315,7 +315,7 @@ static int raw_pull_copy_auxiliary_file( local = strjoina(i->image_root, "/", i->local, suffix); - r = copy_file_atomic(*path, local, 0644, i->force_local, 0); + r = copy_file_atomic(*path, local, 0644, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0)); if (r == -EEXIST) log_warning_errno(r, "File %s already exists, not replacing.", local); else if (r == -ENOENT) @@ -378,7 +378,7 @@ static int raw_pull_make_local_copy(RawPull *i) { if (r < 0) log_warning_errno(r, "Failed to set file attributes on %s: %m", tp); - r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true); + r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK); if (r < 0) { unlink(tp); return log_error_errno(r, "Failed to make writable copy of image: %m"); diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 375ee778e2..91833d6174 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -256,7 +256,7 @@ static int tar_pull_make_local_copy(TarPull *i) { local_settings = strjoina(i->image_root, "/", i->local, ".nspawn"); - r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0); + r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0)); if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); else if (r == -ENOENT) diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 9ba9ee3fc0..79afe6604c 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -24,20 +24,11 @@ #include "parse-util.h" #include "string-util.h" -#define LINE_CHUNK 8*1024u - void source_free(RemoteSource *source) { if (!source) return; - if (source->fd >= 0 && !source->passive_fd) { - log_debug("Closing fd:%d (%s)", source->fd, source->name); - safe_close(source->fd); - } - - free(source->name); - free(source->buf); - iovw_free_contents(&source->iovw); + journal_importer_cleanup(&source->importer); log_debug("Writer ref count %i", source->writer->n_ref); writer_unref(source->writer); @@ -65,442 +56,44 @@ RemoteSource* source_new(int fd, bool passive_fd, char *name, Writer *writer) { if (!source) return NULL; - source->fd = fd; - source->passive_fd = passive_fd; - source->name = name; + source->importer.fd = fd; + source->importer.passive_fd = passive_fd; + source->importer.name = name; + source->writer = writer; return source; } -static char* realloc_buffer(RemoteSource *source, size_t size) { - char *b, *old = source->buf; - - b = GREEDY_REALLOC(source->buf, source->size, size); - if (!b) - return NULL; - - iovw_rebase(&source->iovw, old, source->buf); - - return b; -} - -static int get_line(RemoteSource *source, char **line, size_t *size) { - ssize_t n; - char *c = NULL; - - assert(source); - assert(source->state == STATE_LINE); - assert(source->offset <= source->filled); - assert(source->filled <= source->size); - assert(source->buf == NULL || source->size > 0); - assert(source->fd >= 0); - - for (;;) { - if (source->buf) { - size_t start = MAX(source->scanned, source->offset); - - c = memchr(source->buf + start, '\n', - source->filled - start); - if (c != NULL) - break; - } - - source->scanned = source->filled; - if (source->scanned >= DATA_SIZE_MAX) { - log_error("Entry is bigger than %u bytes.", DATA_SIZE_MAX); - return -E2BIG; - } - - if (source->passive_fd) - /* we have to wait for some data to come to us */ - return -EAGAIN; - - /* We know that source->filled is at most DATA_SIZE_MAX, so if - we reallocate it, we'll increase the size at least a bit. */ - assert_cc(DATA_SIZE_MAX < ENTRY_SIZE_MAX); - if (source->size - source->filled < LINE_CHUNK && - !realloc_buffer(source, MIN(source->filled + LINE_CHUNK, ENTRY_SIZE_MAX))) - return log_oom(); - - assert(source->buf); - assert(source->size - source->filled >= LINE_CHUNK || - source->size == ENTRY_SIZE_MAX); - - n = read(source->fd, - source->buf + source->filled, - source->size - source->filled); - if (n < 0) { - if (errno != EAGAIN) - log_error_errno(errno, "read(%d, ..., %zu): %m", - source->fd, - source->size - source->filled); - return -errno; - } else if (n == 0) - return 0; - - source->filled += n; - } - - *line = source->buf + source->offset; - *size = c + 1 - source->buf - source->offset; - source->offset += *size; - - return 1; -} - -int push_data(RemoteSource *source, const char *data, size_t size) { - assert(source); - assert(source->state != STATE_EOF); - - if (!realloc_buffer(source, source->filled + size)) { - log_error("Failed to store received data of size %zu " - "(in addition to existing %zu bytes with %zu filled): %s", - size, source->size, source->filled, strerror(ENOMEM)); - return -ENOMEM; - } - - memcpy(source->buf + source->filled, data, size); - source->filled += size; - - return 0; -} - -static int fill_fixed_size(RemoteSource *source, void **data, size_t size) { - - assert(source); - assert(source->state == STATE_DATA_START || - source->state == STATE_DATA || - source->state == STATE_DATA_FINISH); - assert(size <= DATA_SIZE_MAX); - assert(source->offset <= source->filled); - assert(source->filled <= source->size); - assert(source->buf != NULL || source->size == 0); - assert(source->buf == NULL || source->size > 0); - assert(source->fd >= 0); - assert(data); - - while (source->filled - source->offset < size) { - int n; - - if (source->passive_fd) - /* we have to wait for some data to come to us */ - return -EAGAIN; - - if (!realloc_buffer(source, source->offset + size)) - return log_oom(); - - n = read(source->fd, source->buf + source->filled, - source->size - source->filled); - if (n < 0) { - if (errno != EAGAIN) - log_error_errno(errno, "read(%d, ..., %zu): %m", source->fd, - source->size - source->filled); - return -errno; - } else if (n == 0) - return 0; - - source->filled += n; - } - - *data = source->buf + source->offset; - source->offset += size; - - return 1; -} - -static int get_data_size(RemoteSource *source) { - int r; - void *data; - - assert(source); - assert(source->state == STATE_DATA_START); - assert(source->data_size == 0); - - r = fill_fixed_size(source, &data, sizeof(uint64_t)); - if (r <= 0) - return r; - - source->data_size = le64toh( *(uint64_t *) data ); - if (source->data_size > DATA_SIZE_MAX) { - log_error("Stream declares field with size %zu > DATA_SIZE_MAX = %u", - source->data_size, DATA_SIZE_MAX); - return -EINVAL; - } - if (source->data_size == 0) - log_warning("Binary field with zero length"); - - return 1; -} - -static int get_data_data(RemoteSource *source, void **data) { - int r; - - assert(source); - assert(data); - assert(source->state == STATE_DATA); - - r = fill_fixed_size(source, data, source->data_size); - if (r <= 0) - return r; - - return 1; -} - -static int get_data_newline(RemoteSource *source) { - int r; - char *data; - - assert(source); - assert(source->state == STATE_DATA_FINISH); - - r = fill_fixed_size(source, (void**) &data, 1); - if (r <= 0) - return r; - - assert(data); - if (*data != '\n') { - log_error("expected newline, got '%c'", *data); - return -EINVAL; - } - - return 1; -} - -static int process_dunder(RemoteSource *source, char *line, size_t n) { - const char *timestamp; - int r; - - assert(line); - assert(n > 0); - assert(line[n-1] == '\n'); - - /* XXX: is it worth to support timestamps in extended format? - * We don't produce them, but who knows... */ - - timestamp = startswith(line, "__CURSOR="); - if (timestamp) - /* ignore __CURSOR */ - return 1; - - timestamp = startswith(line, "__REALTIME_TIMESTAMP="); - if (timestamp) { - long long unsigned x; - line[n-1] = '\0'; - r = safe_atollu(timestamp, &x); - if (r < 0) - log_warning("Failed to parse __REALTIME_TIMESTAMP: '%s'", timestamp); - else - source->ts.realtime = x; - return r < 0 ? r : 1; - } - - timestamp = startswith(line, "__MONOTONIC_TIMESTAMP="); - if (timestamp) { - long long unsigned x; - line[n-1] = '\0'; - r = safe_atollu(timestamp, &x); - if (r < 0) - log_warning("Failed to parse __MONOTONIC_TIMESTAMP: '%s'", timestamp); - else - source->ts.monotonic = x; - return r < 0 ? r : 1; - } - - timestamp = startswith(line, "__"); - if (timestamp) { - log_notice("Unknown dunder line %s", line); - return 1; - } - - /* no dunder */ - return 0; -} - -static int process_data(RemoteSource *source) { - int r; - - switch(source->state) { - case STATE_LINE: { - char *line, *sep; - size_t n = 0; - - assert(source->data_size == 0); - - r = get_line(source, &line, &n); - if (r < 0) - return r; - if (r == 0) { - source->state = STATE_EOF; - return r; - } - assert(n > 0); - assert(line[n-1] == '\n'); - - if (n == 1) { - log_trace("Received empty line, event is ready"); - return 1; - } - - r = process_dunder(source, line, n); - if (r != 0) - return r < 0 ? r : 0; - - /* MESSAGE=xxx\n - or - COREDUMP\n - LLLLLLLL0011223344...\n - */ - sep = memchr(line, '=', n); - if (sep) { - /* chomp newline */ - n--; - - r = iovw_put(&source->iovw, line, n); - if (r < 0) - return r; - } else { - /* replace \n with = */ - line[n-1] = '='; - - source->field_len = n; - source->state = STATE_DATA_START; - - /* we cannot put the field in iovec until we have all data */ - } - - log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary"); - - return 0; /* continue */ - } - - case STATE_DATA_START: - assert(source->data_size == 0); - - r = get_data_size(source); - // log_debug("get_data_size() -> %d", r); - if (r < 0) - return r; - if (r == 0) { - source->state = STATE_EOF; - return 0; - } - - source->state = source->data_size > 0 ? - STATE_DATA : STATE_DATA_FINISH; - - return 0; /* continue */ - - case STATE_DATA: { - void *data; - char *field; - - assert(source->data_size > 0); - - r = get_data_data(source, &data); - // log_debug("get_data_data() -> %d", r); - if (r < 0) - return r; - if (r == 0) { - source->state = STATE_EOF; - return 0; - } - - assert(data); - - field = (char*) data - sizeof(uint64_t) - source->field_len; - memmove(field + sizeof(uint64_t), field, source->field_len); - - r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size); - if (r < 0) - return r; - - source->state = STATE_DATA_FINISH; - - return 0; /* continue */ - } - - case STATE_DATA_FINISH: - r = get_data_newline(source); - // log_debug("get_data_newline() -> %d", r); - if (r < 0) - return r; - if (r == 0) { - source->state = STATE_EOF; - return 0; - } - - source->data_size = 0; - source->state = STATE_LINE; - - return 0; /* continue */ - default: - assert_not_reached("wtf?"); - } -} - int process_source(RemoteSource *source, bool compress, bool seal) { - size_t remain, target; int r; assert(source); assert(source->writer); - r = process_data(source); + r = journal_importer_process_data(&source->importer); if (r <= 0) return r; /* We have a full event */ log_trace("Received full event from source@%p fd:%d (%s)", - source, source->fd, source->name); + source, source->importer.fd, source->importer.name); - if (!source->iovw.count) { + if (source->importer.iovw.count == 0) { log_warning("Entry with no payload, skipping"); goto freeing; } - assert(source->iovw.iovec); - assert(source->iovw.count); + assert(source->importer.iovw.iovec); - r = writer_write(source->writer, &source->iovw, &source->ts, compress, seal); + r = writer_write(source->writer, &source->importer.iovw, &source->importer.ts, compress, seal); if (r < 0) log_error_errno(r, "Failed to write entry of %zu bytes: %m", - iovw_size(&source->iovw)); + iovw_size(&source->importer.iovw)); else r = 1; freeing: - iovw_free_contents(&source->iovw); - - /* possibly reset buffer position */ - remain = source->filled - source->offset; - - if (remain == 0) /* no brainer */ - source->offset = source->scanned = source->filled = 0; - else if (source->offset > source->size - source->filled && - source->offset > remain) { - memcpy(source->buf, source->buf + source->offset, remain); - source->offset = source->scanned = 0; - source->filled = remain; - } - - target = source->size; - while (target > 16 * LINE_CHUNK && source->filled < target / 2) - target /= 2; - if (target < source->size) { - char *tmp; - - tmp = realloc(source->buf, target); - if (!tmp) - log_warning("Failed to reallocate buffer to (smaller) size %zu", - target); - else { - log_debug("Reallocated buffer from %zu to %zu bytes", - source->size, target); - source->buf = tmp; - source->size = target; - } - } - + journal_importer_drop_iovw(&source->importer); return r; } diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 1740a21f92..e3632528cf 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -21,34 +21,11 @@ #include "sd-event.h" +#include "journal-importer.h" #include "journal-remote-write.h" -typedef enum { - STATE_LINE = 0, /* waiting to read, or reading line */ - STATE_DATA_START, /* reading binary data header */ - STATE_DATA, /* reading binary data */ - STATE_DATA_FINISH, /* expecting newline */ - STATE_EOF, /* done */ -} source_state; - typedef struct RemoteSource { - char *name; - int fd; - bool passive_fd; - - char *buf; - size_t size; /* total size of the buffer */ - size_t offset; /* offset to the beginning of live data in the buffer */ - size_t scanned; /* number of bytes since the beginning of data without a newline */ - size_t filled; /* total number of bytes in the buffer */ - - size_t field_len; /* used for binary fields: the field name length */ - size_t data_size; /* and the size of the binary data chunk being processed */ - - struct iovec_wrapper iovw; - - source_state state; - dual_timestamp ts; + JournalImporter importer; Writer *writer; @@ -57,13 +34,5 @@ typedef struct RemoteSource { } RemoteSource; RemoteSource* source_new(int fd, bool passive_fd, char *name, Writer *writer); - -static inline size_t source_non_empty(RemoteSource *source) { - assert(source); - - return source->filled; -} - void source_free(RemoteSource *source); -int push_data(RemoteSource *source, const char *data, size_t size); int process_source(RemoteSource *source, bool compress, bool seal); diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 8729372aa3..734cad333f 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -20,39 +20,6 @@ #include "alloc-util.h" #include "journal-remote.h" -int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { - if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1)) - return log_oom(); - - iovw->iovec[iovw->count++] = (struct iovec) {data, len}; - return 0; -} - -void iovw_free_contents(struct iovec_wrapper *iovw) { - iovw->iovec = mfree(iovw->iovec); - iovw->size_bytes = iovw->count = 0; -} - -size_t iovw_size(struct iovec_wrapper *iovw) { - size_t n = 0, i; - - for (i = 0; i < iovw->count; i++) - n += iovw->iovec[i].iov_len; - - return n; -} - -void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) { - size_t i; - - for (i = 0; i < iovw->count; i++) - iovw->iovec[i].iov_base = (char*) iovw->iovec[i].iov_base - old + new; -} - -/********************************************************************** - ********************************************************************** - **********************************************************************/ - static int do_rotate(JournalFile **f, bool compress, bool seal) { int r = journal_file_rotate(f, compress, seal, NULL); if (r < 0) { diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 53ba45fc04..e04af54e55 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -20,20 +20,10 @@ ***/ #include "journal-file.h" +#include "journal-importer.h" typedef struct RemoteServer RemoteServer; -struct iovec_wrapper { - struct iovec *iovec; - size_t size_bytes; - size_t count; -}; - -int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len); -void iovw_free_contents(struct iovec_wrapper *iovw); -size_t iovw_size(struct iovec_wrapper *iovw); -void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new); - typedef struct Writer { JournalFile *journal; JournalMetrics metrics; diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index d0d8d936e3..202a5a3f97 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -512,7 +512,8 @@ static int process_http_upload( if (*upload_data_size) { log_trace("Received %zu bytes", *upload_data_size); - r = push_data(source, upload_data, *upload_data_size); + r = journal_importer_push_data(&source->importer, + upload_data, *upload_data_size); if (r < 0) return mhd_respond_oom(connection); @@ -542,7 +543,7 @@ static int process_http_upload( /* The upload is finished */ - remaining = source_non_empty(source); + remaining = journal_importer_bytes_remaining(&source->importer); if (remaining > 0) { log_warning("Premature EOF byte. %zu bytes lost.", remaining); return mhd_respondf(connection, @@ -1036,19 +1037,19 @@ static int handle_raw_source(sd_event_source *event, assert(fd >= 0 && fd < (ssize_t) s->sources_size); source = s->sources[fd]; - assert(source->fd == fd); + assert(source->importer.fd == fd); r = process_source(source, arg_compress, arg_seal); - if (source->state == STATE_EOF) { + if (journal_importer_eof(&source->importer)) { size_t remaining; - log_debug("EOF reached with source fd:%d (%s)", - source->fd, source->name); + log_debug("EOF reached with source %s (fd=%d)", + source->importer.name, source->importer.fd); - remaining = source_non_empty(source); + remaining = journal_importer_bytes_remaining(&source->importer); if (remaining > 0) log_notice("Premature EOF. %zu bytes lost.", remaining); - remove_source(s, source->fd); + remove_source(s, source->importer.fd); log_debug("%zu active sources remaining", s->active); return 0; } else if (r == -E2BIG) { @@ -1072,7 +1073,7 @@ static int dispatch_raw_source_until_block(sd_event_source *event, /* Make sure event stays around even if source is destroyed */ sd_event_source_ref(event); - r = handle_raw_source(event, source->fd, EPOLLIN, server); + r = handle_raw_source(event, source->importer.fd, EPOLLIN, server); if (r != 1) /* No more data for now */ sd_event_source_set_enabled(event, SD_EVENT_OFF); @@ -1105,7 +1106,7 @@ static int dispatch_blocking_source_event(sd_event_source *event, void *userdata) { RemoteSource *source = userdata; - return handle_raw_source(event, source->fd, EPOLLIN, server); + return handle_raw_source(event, source->importer.fd, EPOLLIN, server); } static int accept_connection(const char* type, int fd, diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index 18c8644507..8afaec0ced 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -156,7 +156,8 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) { /* Did we lose any? */ if (serial > *s->kernel_seqnum) - server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, + server_driver_message(s, + "MESSAGE_ID=" SD_MESSAGE_JOURNAL_MISSED_STR, LOG_MESSAGE("Missed %"PRIu64" kernel messages", serial - *s->kernel_seqnum), NULL); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 0a1ce205c2..3c03b83754 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -27,6 +27,7 @@ #include "fd-util.h" #include "fs-util.h" #include "io-util.h" +#include "journal-importer.h" #include "journald-console.h" #include "journald-kmsg.h" #include "journald-native.h" diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h index c13b80aa4f..1ab415ac85 100644 --- a/src/journal/journald-native.h +++ b/src/journal/journald-native.h @@ -21,11 +21,6 @@ #include "journald-server.h" -/* Make sure not to make this smaller than the maximum coredump - * size. See COREDUMP_MAX in coredump.c */ -#define ENTRY_SIZE_MAX (1024*1024*770u) -#define DATA_SIZE_MAX (1024*1024*768u) - bool valid_user_field(const char *p, size_t l, bool allow_protected); void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 8b92ea3def..451f16483f 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -214,7 +214,7 @@ void server_space_usage_message(Server *s, JournalStorage *storage) { format_bytes(fb5, sizeof(fb5), storage->space.limit); format_bytes(fb6, sizeof(fb6), storage->space.available); - server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE, + server_driver_message(s, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_USAGE_STR, LOG_MESSAGE("%s (%s) is %s, max %s, %s free.", storage->name, storage->path, fb1, fb5, fb6), "JOURNAL_NAME=%s", storage->name, @@ -1061,8 +1061,7 @@ static void dispatch_message_real( write_to_journal(s, journal_uid, iovec, n, priority); } -void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) { - char mid[11 + 32 + 1]; +void server_driver_message(Server *s, const char *message_id, const char *format, ...) { struct iovec iovec[N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS]; unsigned n = 0, m; int r; @@ -1080,11 +1079,8 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format, assert_cc(6 == LOG_INFO); IOVEC_SET_STRING(iovec[n++], "PRIORITY=6"); - if (!sd_id128_is_null(message_id)) { - snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id)); - IOVEC_SET_STRING(iovec[n++], mid); - } - + if (message_id) + IOVEC_SET_STRING(iovec[n++], message_id); m = n; va_start(ap, format); @@ -1174,7 +1170,7 @@ void server_dispatch_message( /* Write a suppression message if we suppressed something */ if (rl > 1) - server_driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, + server_driver_message(s, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_DROPPED_STR, LOG_MESSAGE("Suppressed %u messages from %s", rl - 1, path), NULL); @@ -1273,7 +1269,7 @@ finish: sd_journal_close(j); - server_driver_message(s, SD_ID128_NULL, + server_driver_message(s, NULL, LOG_MESSAGE("Time spent on flushing to /var is %s for %u entries.", format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), n), diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 716e758b7c..75ac114d24 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -176,7 +176,7 @@ struct Server { #define N_IOVEC_PAYLOAD_FIELDS 15 void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid); -void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,0) _sentinel_; +void server_driver_message(Server *s, const char *message_id, const char *format, ...) _printf_(3,0) _sentinel_; /* gperf lookup function */ const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TYPE length); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index 896303fb85..474369039a 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -444,7 +444,8 @@ void server_maybe_warn_forward_syslog_missed(Server *s) { if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n) return; - server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, + server_driver_message(s, + "MESSAGE_ID=" SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR, LOG_MESSAGE("Forwarding to syslog missed %u messages.", s->n_forward_syslog_missed), NULL); diff --git a/src/journal/journald.c b/src/journal/journald.c index 54fd1f999d..1aaef387b4 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -56,7 +56,8 @@ int main(int argc, char *argv[]) { server_flush_dev_kmsg(&server); log_debug("systemd-journald running as pid "PID_FMT, getpid()); - server_driver_message(&server, SD_MESSAGE_JOURNAL_START, + server_driver_message(&server, + "MESSAGE_ID=" SD_MESSAGE_JOURNAL_START_STR, LOG_MESSAGE("Journal started"), NULL); @@ -114,7 +115,8 @@ int main(int argc, char *argv[]) { } log_debug("systemd-journald stopped as pid "PID_FMT, getpid()); - server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, + server_driver_message(&server, + "MESSAGE_ID=" SD_MESSAGE_JOURNAL_STOP_STR, LOG_MESSAGE("Journal stopped"), NULL); diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 4dd343c101..2ebc00f247 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -242,8 +242,6 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) goto fail; - - acd->n_conflict = 0; } else { r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); if (r < 0) diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 90fb93bbaf..d739af8ea2 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -155,7 +155,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u case KEY_POWER2: log_struct(LOG_INFO, LOG_MESSAGE("Power key pressed."), - LOG_MESSAGE_ID(SD_MESSAGE_POWER_KEY), + "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR, NULL); manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true); @@ -170,7 +170,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u case KEY_SLEEP: log_struct(LOG_INFO, LOG_MESSAGE("Suspend key pressed."), - LOG_MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY), + "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR, NULL); manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true); @@ -179,7 +179,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u case KEY_SUSPEND: log_struct(LOG_INFO, LOG_MESSAGE("Hibernate key pressed."), - LOG_MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY), + "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR, NULL); manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true); @@ -191,7 +191,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u if (ev.code == SW_LID) { log_struct(LOG_INFO, LOG_MESSAGE("Lid closed."), - LOG_MESSAGE_ID(SD_MESSAGE_LID_CLOSED), + "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR, NULL); b->lid_closed = true; @@ -201,7 +201,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u } else if (ev.code == SW_DOCK) { log_struct(LOG_INFO, LOG_MESSAGE("System docked."), - LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED), + "MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR, NULL); b->docked = true; @@ -212,7 +212,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u if (ev.code == SW_LID) { log_struct(LOG_INFO, LOG_MESSAGE("Lid opened."), - LOG_MESSAGE_ID(SD_MESSAGE_LID_OPENED), + "MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR, NULL); b->lid_closed = false; @@ -221,7 +221,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u } else if (ev.code == SW_DOCK) { log_struct(LOG_INFO, LOG_MESSAGE("System undocked."), - LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED), + "MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR, NULL); b->docked = false; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index ad44ca290e..c6be596af3 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1430,7 +1430,7 @@ static int bus_manager_log_shutdown( p = strjoina(p, " (", m->wall_message, ")."); return log_struct(LOG_NOTICE, - LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN), + "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, p, q, NULL); diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index bfbd07309d..e4836fcaab 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -416,7 +416,7 @@ int seat_start(Seat *s) { return 0; log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SEAT_START), + "MESSAGE_ID=" SD_MESSAGE_SEAT_START_STR, "SEAT_ID=%s", s->id, LOG_MESSAGE("New seat %s.", s->id), NULL); @@ -444,7 +444,7 @@ int seat_stop(Seat *s, bool force) { if (s->started) log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SEAT_STOP), + "MESSAGE_ID=" SD_MESSAGE_SEAT_STOP_STR, "SEAT_ID=%s", s->id, LOG_MESSAGE("Removed seat %s.", s->id), NULL); diff --git a/src/login/logind-session.c b/src/login/logind-session.c index fd7fcf7f2c..4a168906d6 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -561,7 +561,7 @@ int session_start(Session *s) { return r; log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START), + "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR, "SESSION_ID=%s", s->id, "USER_ID=%s", s->user->name, "LEADER="PID_FMT, s->leader, @@ -666,7 +666,7 @@ int session_finalize(Session *s) { if (s->started) log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP), + "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR, "SESSION_ID=%s", s->id, "USER_ID=%s", s->user->name, "LEADER="PID_FMT, s->leader, diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index d5051007fc..2f69e2c7b7 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -374,7 +374,7 @@ static int raw_image_get_os_release(Image *image, char ***ret, sd_bus_error *err if (fd < 0) _exit(EXIT_FAILURE); - r = copy_bytes(fd, pair[1], (uint64_t) -1, false); + r = copy_bytes(fd, pair[1], (uint64_t) -1, 0); if (r < 0) _exit(EXIT_FAILURE); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index af745b6567..36568b65ef 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -411,7 +411,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s if (fd < 0) _exit(EXIT_FAILURE); - r = copy_bytes(fd, pair[1], (uint64_t) -1, false); + r = copy_bytes(fd, pair[1], (uint64_t) -1, 0); if (r < 0) _exit(EXIT_FAILURE); @@ -841,6 +841,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu int read_only, make_directory; pid_t child; siginfo_t si; + uid_t uid; int r; assert(message); @@ -875,6 +876,12 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu if (r == 0) return 1; /* Will call us back */ + r = machine_get_uid_shift(m, &uid); + if (r < 0) + return r; + if (uid != 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied."); + /* One day, when bind mounting /proc/self/fd/n works across * namespace boundaries we should rework this logic to make * use of it... */ @@ -1055,10 +1062,12 @@ finish: int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) { const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname; _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; + CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE; _cleanup_close_ int hostfd = -1; Machine *m = userdata; bool copy_from; pid_t child; + uid_t uid_shift; char *t; int r; @@ -1097,6 +1106,10 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro if (r == 0) return 1; /* Will call us back */ + r = machine_get_uid_shift(m, &uid_shift); + if (r < 0) + return r; + copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom"); if (copy_from) { @@ -1151,10 +1164,13 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro goto child_fail; } + /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to + * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy + * the UID/GIDs as they are. */ if (copy_from) - r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true); + r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags); else - r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true); + r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags); hostfd = safe_close(hostfd); containerfd = safe_close(containerfd); @@ -1276,6 +1292,32 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda return sd_bus_reply_method_return(message, "h", fd); } +int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Machine *m = userdata; + uid_t shift = 0; + int r; + + assert(message); + assert(m); + + /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but + * we kinda have to for this. */ + + if (m->class == MACHINE_HOST) + return sd_bus_reply_method_return(message, "u", UINT32_C(0)); + + if (m->class != MACHINE_CONTAINER) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines."); + + r = machine_get_uid_shift(m, &shift); + if (r == -ENXIO) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, "u", (uint32_t) shift); +} + const sd_bus_vtable machine_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1293,6 +1335,7 @@ const sd_bus_vtable machine_vtable[] = { SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUIDShift", NULL, "u", bus_machine_method_get_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h index c513783480..2aa7b4ce06 100644 --- a/src/machine/machine-dbus.h +++ b/src/machine/machine-dbus.h @@ -39,6 +39,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error); int machine_send_signal(Machine *m, bool new_machine); int machine_send_create_reply(Machine *m, sd_bus_error *error); diff --git a/src/machine/machine.c b/src/machine/machine.c index eb4b35d52a..d3433d9b96 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -38,6 +38,7 @@ #include "parse-util.h" #include "process-util.h" #include "special.h" +#include "stdio-util.h" #include "string-table.h" #include "terminal-util.h" #include "unit-name.h" @@ -401,7 +402,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) { return r; log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START), + "MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR, "NAME=%s", m->name, "LEADER="PID_FMT, m->leader, LOG_MESSAGE("New machine %s.", m->name), @@ -464,7 +465,7 @@ int machine_finalize(Machine *m) { if (m->started) log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP), + "MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR, "NAME=%s", m->name, "LEADER="PID_FMT, m->leader, LOG_MESSAGE("Machine %s terminated.", m->name), @@ -604,6 +605,96 @@ void machine_release_unit(Machine *m) { m->unit = mfree(m->unit); } +int machine_get_uid_shift(Machine *m, uid_t *ret) { + char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1]; + uid_t uid_base, uid_shift, uid_range; + gid_t gid_base, gid_shift, gid_range; + _cleanup_fclose_ FILE *f = NULL; + int k; + + assert(m); + assert(ret); + + /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple + * mappings. In most cases setups should be simple like this, and administrators should only care about the + * basic offset a container has relative to the host. This is what this function exposes. + * + * If we encounter any more complex mappings we politely refuse this with ENXIO. */ + + if (m->class == MACHINE_HOST) { + *ret = 0; + return 0; + } + + if (m->class != MACHINE_CONTAINER) + return -EOPNOTSUPP; + + xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader); + f = fopen(p, "re"); + if (!f) { + if (errno == ENOENT) { + /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */ + *ret = 0; + return 0; + } + + return -errno; + } + + /* Read the first line. There's at least one. */ + errno = 0; + k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range); + if (k != 3) { + if (ferror(f)) + return -errno; + + return -EBADMSG; + } + + /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */ + if (uid_base != 0) + return -ENXIO; + /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */ + if (uid_range < (uid_t) 65534U) + return -ENXIO; + + /* If there's more than one line, then we don't support this mapping. */ + if (fgetc(f) != EOF) + return -ENXIO; + + fclose(f); + + xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader); + f = fopen(p, "re"); + if (!f) + return -errno; + + /* Read the first line. There's at least one. */ + errno = 0; + k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range); + if (k != 3) { + if (ferror(f)) + return -errno; + + return -EBADMSG; + } + + /* If there's more than one line, then we don't support this file. */ + if (fgetc(f) != EOF) + return -ENXIO; + + /* If the UID and GID mapping doesn't match, we don't support this mapping. */ + if (uid_base != (uid_t) gid_base) + return -ENXIO; + if (uid_shift != (uid_t) gid_shift) + return -ENXIO; + if (uid_range != (uid_t) gid_range) + return -ENXIO; + + *ret = uid_shift; + return 0; +} + static const char* const machine_class_table[_MACHINE_CLASS_MAX] = { [MACHINE_CONTAINER] = "container", [MACHINE_VM] = "vm", diff --git a/src/machine/machine.h b/src/machine/machine.h index e5d75361a9..6bdb204ed6 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -108,3 +108,5 @@ KillWho kill_who_from_string(const char *s) _pure_; int machine_openpt(Machine *m, int flags); int machine_open_terminal(Machine *m, const char *path, int mode); + +int machine_get_uid_shift(Machine *m, uid_t *ret); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index fe4f1b7726..28384286fb 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -327,8 +327,10 @@ static int list_machines(int argc, char *argv[], void *userdata) { (int) max_version_id, strdash_if_empty(machines[j].version_id)); r = print_addresses(bus, machines[j].name, 0, "", prefix, arg_addrs); - if (r == -EOPNOTSUPP) - printf("-\n"); + if (r <= 0) /* error or no addresses defined? */ + fputs("-\n", stdout); + else + fputc('\n', stdout); } if (arg_legend) { @@ -520,6 +522,7 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *addresses = NULL; bool truncate = false; + unsigned n = 0; int r; assert(bus); @@ -567,7 +570,7 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p else strcpy(buf_ifi, ""); - if(!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL)) + if (!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL)) return log_oom(); } else truncate = true; @@ -581,6 +584,8 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p if (n_addr > 0) n_addr -= 1; + + n++; } if (r < 0) return bus_log_parse_error(r); @@ -589,8 +594,10 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p if (r < 0) return bus_log_parse_error(r); - fprintf(stdout, "%s%s\n", addresses, truncate ? "..." : ""); - return 0; + if (n > 0) + fprintf(stdout, "%s%s", addresses, truncate ? "..." : ""); + + return (int) n; } static int print_os_release(sd_bus *bus, const char *method, const char *name, const char *prefix) { @@ -611,6 +618,37 @@ static int print_os_release(sd_bus *bus, const char *method, const char *name, c return 0; } +static int print_uid_shift(sd_bus *bus, const char *name) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + uint32_t shift; + int r; + + assert(bus); + assert(name); + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachineUIDShift", + &error, + &reply, + "s", name); + if (r < 0) + return log_debug_errno(r, "Failed to query UID/GID shift: %s", bus_error_message(&error, r)); + + r = sd_bus_message_read(reply, "u", &shift); + if (r < 0) + return r; + + if (shift == 0) /* Don't show trivial mappings */ + return 0; + + printf(" UID Shift: %" PRIu32 "\n", shift); + return 0; +} + typedef struct MachineStatusInfo { char *name; sd_id128_t id; @@ -707,13 +745,16 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) { fputc('\n', stdout); } - print_addresses(bus, i->name, ifi, - "\t Address: ", - "\n\t ", - ALL_IP_ADDRESSES); + if (print_addresses(bus, i->name, ifi, + "\t Address: ", + "\n\t ", + ALL_IP_ADDRESSES) > 0) + fputc('\n', stdout); print_os_release(bus, "GetMachineOSRelease", i->name, "\t OS: "); + print_uid_shift(bus, i->name); + if (i->unit) { printf("\t Unit: %s\n", i->unit); show_unit_cgroup(bus, i->unit, i->leader); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index fd9e5b56fc..c9b92d2765 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -729,6 +729,26 @@ static int method_open_machine_root_directory(sd_bus_message *message, void *use return bus_machine_method_open_root_directory(message, machine, error); } +static int method_get_machine_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + const char *name; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + return bus_machine_method_get_uid_shift(message, machine, error); +} + static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(image_unrefp) Image* i = NULL; const char *name; @@ -1416,6 +1436,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/machine/operation.c b/src/machine/operation.c index c966d0d21c..f7d5310f44 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -61,8 +61,10 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat } else { /* The default operation when done is to simply return an error on failure or an empty success * message on success. */ - if (r < 0) + if (r < 0) { + sd_bus_error_set_errno(&error, r); goto fail; + } r = sd_bus_reply_method_return(o->message, NULL); if (r < 0) diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf index 82ebfba50c..daa365a9dd 100644 --- a/src/machine/org.freedesktop.machine1.conf +++ b/src/machine/org.freedesktop.machine1.conf @@ -66,6 +66,10 @@ <allow send_destination="org.freedesktop.machine1" send_interface="org.freedesktop.machine1.Manager" + send_member="GetMachineUIDShift"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" send_member="OpenMachineLogin"/> <allow send_destination="org.freedesktop.machine1" @@ -150,6 +154,10 @@ <allow send_destination="org.freedesktop.machine1" send_interface="org.freedesktop.machine1.Machine" + send_member="GetUIDShift"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Machine" send_member="OpenLogin"/> <allow send_destination="org.freedesktop.machine1" diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index b172b44933..efd3b014a3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1364,7 +1364,7 @@ static int setup_resolv_conf(const char *dest) { } /* If that didn't work, let's copy the file */ - r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0); + r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0, COPY_REFLINK); if (r < 0) { /* If the file already exists as symlink, let's suppress the warning, under the assumption that * resolved or something similar runs inside and the symlink points there. @@ -3700,7 +3700,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL); + r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, COPY_REFLINK); if (r < 0) { r = log_error_errno(r, "Failed to copy image file: %m"); goto finish; @@ -3856,7 +3856,7 @@ finish: /* Try to flush whatever is still queued in the pty */ if (master >= 0) { - (void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, false); + (void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, 0); master = safe_close(master); } diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 326672cab5..0570fde592 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -114,8 +114,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r( l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2); if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = NO_RECOVERY; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -220,8 +220,8 @@ static enum nss_status fill_in_hostent( (c > 0 ? c+1 : 2) * sizeof(char*); if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = NO_RECOVERY; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index fac37faea5..ea90953abb 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -151,8 +151,8 @@ enum nss_status _nss_mymachines_gethostbyname4_r( l = strlen(name); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -306,8 +306,8 @@ enum nss_status _nss_mymachines_gethostbyname3_r( ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = NO_RECOVERY; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -471,7 +471,7 @@ enum nss_status _nss_mymachines_getpwnam_r( l = strlen(name); if (buflen < l+1) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -550,7 +550,7 @@ enum nss_status _nss_mymachines_getpwuid_r( goto not_found; if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -645,7 +645,7 @@ enum nss_status _nss_mymachines_getgrnam_r( l = sizeof(char*) + strlen(name) + 1; if (buflen < l) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -722,13 +722,13 @@ enum nss_status _nss_mymachines_getgrgid_r( goto not_found; if (buflen < sizeof(char*) + 1) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } memzero(buffer, sizeof(char*)); if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index ce8d59d390..d155625e11 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -118,7 +118,7 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) { /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */ - assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET)); + assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6)); memcpy(&in6, a, sizeof(struct in6_addr)); return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0; @@ -206,8 +206,8 @@ enum nss_status _nss_resolve_gethostbyname4_r( l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -394,8 +394,8 @@ enum nss_status _nss_resolve_gethostbyname3_r( ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -615,8 +615,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( c * sizeof(char*); /* pointers to aliases, plus trailing NULL */ if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index fd5064c937..f404755dac 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -185,7 +185,7 @@ enum nss_status _nss_systemd_getpwnam_r( l = strlen(name); if (buflen < l+1) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -286,7 +286,7 @@ enum nss_status _nss_systemd_getpwuid_r( l = strlen(translated) + 1; if (buflen < l) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -386,7 +386,7 @@ enum nss_status _nss_systemd_getgrnam_r( l = sizeof(char*) + strlen(name) + 1; if (buflen < l) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -484,7 +484,7 @@ enum nss_status _nss_systemd_getgrgid_r( l = sizeof(char*) + strlen(translated) + 1; if (buflen < l) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 10562d03ec..072cbfca1a 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -570,7 +570,7 @@ void dns_server_warn_downgrade(DnsServer *server) { return; log_struct(LOG_NOTICE, - LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_DOWNGRADE), + "MESSAGE_ID=" SD_MESSAGE_DNSSEC_DOWNGRADE_STR, LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", dns_server_string(server)), "DNS_SERVER=%s", dns_server_string(server), "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(server->possible_feature_level), diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 69e1d58ccf..9687409663 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -318,7 +318,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { dns_resource_key_to_string(t->key, key_str, sizeof key_str); log_struct(LOG_NOTICE, - LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_FAILURE), + "MESSAGE_ID=" SD_MESSAGE_DNSSEC_FAILURE_STR, LOG_MESSAGE("DNSSEC validation failed for question %s: %s", key_str, dnssec_result_to_string(t->answer_dnssec_result)), "DNS_TRANSACTION=%" PRIu16, t->id, "DNS_QUESTION=%s", key_str, diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c index 9917b9e984..d8529f8317 100644 --- a/src/resolve/resolved-dns-trust-anchor.c +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -594,7 +594,7 @@ static int dns_trust_anchor_remove_revoked(DnsTrustAnchor *d, DnsResourceRecord /* We found the key! Warn the user */ log_struct(LOG_WARNING, - LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED), + "MESSAGE_ID=" SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR, LOG_MESSAGE("DNSSEC Trust anchor %s has been revoked. Please update the trust anchor, or upgrade your operating system."), strna(dns_resource_record_to_string(rr)), "TRUST_ANCHOR=%s", dns_resource_record_to_string(rr), NULL); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 791c125613..c4e4409fe3 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -332,19 +332,18 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char assert(llmnr_hostname); assert(mdns_hostname); - /* Extract and normalize the first label of the locally - * configured hostname, and check it's not "localhost". */ + /* Extract and normalize the first label of the locally configured hostname, and check it's not "localhost". */ - h = gethostname_malloc(); - if (!h) - return log_oom(); + r = gethostname_strict(&h); + if (r < 0) + return log_debug_errno(r, "Can't determine system hostname: %m"); p = h; r = dns_label_unescape(&p, label, sizeof(label)); if (r < 0) return log_error_errno(r, "Failed to unescape host name: %m"); if (r == 0) { - log_error("Couldn't find a single label in hosntame."); + log_error("Couldn't find a single label in hostname."); return -EINVAL; } @@ -381,6 +380,57 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char return 0; } +static const char *fallback_hostname(void) { + + /* Determine the fall back hostname. For exposing this system to the outside world, we cannot have it to be + * "localhost" even if that's the compiled in hostname. In this case, let's revert to "linux" instead. */ + + if (is_localhost(FALLBACK_HOSTNAME)) + return "linux"; + + return FALLBACK_HOSTNAME; +} + +static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) { + _cleanup_free_ char *n = NULL, *m = NULL; + char label[DNS_LABEL_MAX], *h; + const char *p; + int r; + + assert(full_hostname); + assert(llmnr_hostname); + assert(mdns_hostname); + + p = fallback_hostname(); + r = dns_label_unescape(&p, label, sizeof(label)); + if (r < 0) + return log_error_errno(r, "Failed to unescape fallback host name: %m"); + + assert(r > 0); /* The fallback hostname must have at least one label */ + + r = dns_label_escape_new(label, r, &n); + if (r < 0) + return log_error_errno(r, "Failed to escape fallback hostname: %m"); + + r = dns_name_concat(n, "local", &m); + if (r < 0) + return log_error_errno(r, "Failed to concatenate mDNS hostname: %m"); + + h = strdup(fallback_hostname()); + if (!h) + return log_oom(); + + *llmnr_hostname = n; + n = NULL; + + *mdns_hostname = m; + m = NULL; + + *full_hostname = h; + + return 0; +} + static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) { _cleanup_free_ char *full_hostname = NULL, *llmnr_hostname = NULL, *mdns_hostname = NULL; Manager *m = userdata; @@ -432,19 +482,11 @@ static int manager_watch_hostname(Manager *m) { r = determine_hostname(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { - log_info("Defaulting to hostname 'linux'."); - - m->full_hostname = strdup("linux"); - if (!m->full_hostname) - return log_oom(); - - m->llmnr_hostname = strdup("linux"); - if (!m->llmnr_hostname) - return log_oom(); + log_info("Defaulting to hostname '%s'.", fallback_hostname()); - m->mdns_hostname = strdup("linux.local"); - if (!m->mdns_hostname) - return log_oom(); + r = make_fallback_hostnames(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); + if (r < 0) + return r; } else log_info("Using system hostname '%s'.", m->full_hostname); diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 3ca7e78495..8cbe492526 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -29,10 +29,9 @@ #include "resolved-dns-rr.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "unaligned.h" -#include "test-helper.h" - #define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1) static void verify_rr_copy(DnsResourceRecord *rr) { @@ -117,7 +116,7 @@ int main(int argc, char **argv) { N = argc - 1; fnames = argv + 1; } else { - assert_se(glob(TEST_DATA_DIR("/test-resolve/*.pkts"), GLOB_NOSORT, NULL, &g) == 0); + assert_se(glob(get_testdata_dir("/test-resolve/*.pkts"), GLOB_NOSORT, NULL, &g) == 0); N = g.gl_pathc; fnames = g.gl_pathv; } diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 7bc5c0a128..d96ff44e66 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -594,7 +594,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch if (!rs) return -ENOMEM; - return copy_file_atomic(path, rs, 0664, false, 0); + return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK); } int image_clone(Image *i, const char *new_name, bool read_only) { @@ -656,7 +656,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) { case IMAGE_RAW: new_path = strjoina("/var/lib/machines/", new_name, ".raw"); - r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false, FS_NOCOW_FL); + r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK); break; default: diff --git a/src/shared/pager.c b/src/shared/pager.c index 09672a4abf..af667a83f4 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -44,7 +44,7 @@ static pid_t pager_pid = 0; noreturn static void pager_fallback(void) { int r; - r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, false); + r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0); if (r < 0) { log_error_errno(r, "Internal pager failed: %m"); _exit(EXIT_FAILURE); diff --git a/src/shared/tests.c b/src/shared/tests.c index 7034687725..f300bbc66f 100644 --- a/src/shared/tests.c +++ b/src/shared/tests.c @@ -24,6 +24,7 @@ #include <util.h> #include "tests.h" +#include "path-util.h" char* setup_fake_runtime_dir(void) { char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p; @@ -35,12 +36,38 @@ char* setup_fake_runtime_dir(void) { return p; } -const char* get_exe_relative_testdata_dir(void) { - _cleanup_free_ char *exedir = NULL; +const char* get_testdata_dir(const char *suffix) { + const char *env; /* convenience: caller does not need to free result */ static char testdir[PATH_MAX]; - assert_se(readlink_and_make_absolute("/proc/self/exe", &exedir) >= 0); - assert_se(snprintf(testdir, sizeof(testdir), "%s/testdata", dirname(exedir)) > 0); + /* if the env var is set, use that */ + env = getenv("SYSTEMD_TEST_DATA"); + testdir[sizeof(testdir) - 1] = '\0'; + if (env) { + if (access(env, F_OK) < 0) { + fputs("ERROR: $SYSTEMD_TEST_DATA directory does not exist\n", stderr); + exit(1); + } + strncpy(testdir, env, sizeof(testdir) - 1); + } else { + _cleanup_free_ char *exedir = NULL; + assert_se(readlink_and_make_absolute("/proc/self/exe", &exedir) >= 0); + + /* Check if we're running from the builddir. If so, use the compiled in path. */ + if (path_startswith(exedir, ABS_BUILD_DIR)) + assert_se(snprintf(testdir, sizeof(testdir), "%s/test", ABS_SRC_DIR) > 0); + else + /* Try relative path, according to the install-test layout */ + assert_se(snprintf(testdir, sizeof(testdir), "%s/testdata", dirname(exedir)) > 0); + + /* test this without the suffix, as it may contain a glob */ + if (access(testdir, F_OK) < 0) { + fputs("ERROR: Cannot find testdata directory, set $SYSTEMD_TEST_DATA\n", stderr); + exit(1); + } + } + + strncpy(testdir + strlen(testdir), suffix, sizeof(testdir) - strlen(testdir) - 1); return testdir; } diff --git a/src/shared/tests.h b/src/shared/tests.h index 0100b48937..7055124990 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -20,4 +20,4 @@ ***/ char* setup_fake_runtime_dir(void); -const char* get_exe_relative_testdata_dir(void); +const char* get_testdata_dir(const char *suffix); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index c8f0742183..ea96615222 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -109,7 +109,7 @@ static int execute(char **modes, char **states) { execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments); log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START), + "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR, LOG_MESSAGE("Suspending system..."), "SLEEP=%s", arg_verb, NULL); @@ -119,7 +119,7 @@ static int execute(char **modes, char **states) { return r; log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP), + "MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR, LOG_MESSAGE("System resumed."), "SLEEP=%s", arg_verb, NULL); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 2336ae34f4..60f8bc3df5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5300,7 +5300,7 @@ static int cat_file(const char *filename, bool newline) { ansi_normal()); fflush(stdout); - return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false); + return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0); } static int cat(int argc, char *argv[], void *userdata) { @@ -6582,7 +6582,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path if (r < 0) return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path); - r = copy_file(original_path, t, 0, 0644, 0); + r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK); if (r == -ENOENT) { r = touch(t); diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index 6cc8e4ac0e..9b38969b77 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -100,6 +100,9 @@ int sd_id128_get_invocation(sd_id128_t *ret); ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ 0 }) +#define SD_ID128_MAKE_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + #a #b #c #d #e #f #g #h #i #j #k #l #m #n #o #p + _sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) { return memcmp(&a, &b, 16) == 0; } diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index db1a21be05..f466d9b062 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -33,60 +33,109 @@ _SD_BEGIN_DECLARATIONS; * with journalctl --new-id128. Do not use any other IDs, and do not * count them up manually. */ -#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b) -#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b) -#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e) -#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06) -#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6) - -#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) -#define SD_MESSAGE_TRUNCATED_CORE SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37) - -#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66) -#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a) -#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b) -#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5) -#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2) -#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58) - -#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27) -#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90) - -#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff) -#define SD_MESSAGE_USER_STARTUP_FINISHED SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1) - -#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28) -#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14) - -#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40) - -#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5) -#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf) -#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f) -#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86) -#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d) -#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25) -#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54) - -#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7) - -#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e) - -#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7) - -#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f) -#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70) -#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff) -#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53) -#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71) -#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72) -#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73) - -#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01) - -#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d) -#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65) -#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57) +#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b) +#define SD_MESSAGE_JOURNAL_START_STR SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b) +#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b) +#define SD_MESSAGE_JOURNAL_STOP_STR SD_ID128_MAKE_STR(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b) +#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e) +#define SD_MESSAGE_JOURNAL_DROPPED_STR SD_ID128_MAKE_STR(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e) +#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06) +#define SD_MESSAGE_JOURNAL_MISSED_STR SD_ID128_MAKE_STR(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06) +#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6) +#define SD_MESSAGE_JOURNAL_USAGE_STR SD_ID128_MAKE_STR(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6) + +#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) +#define SD_MESSAGE_COREDUMP_STR SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) +#define SD_MESSAGE_TRUNCATED_CORE SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37) +#define SD_MESSAGE_TRUNCATED_CORE_STR SD_ID128_MAKE_STR(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37) +#define SD_MESSAGE_BACKTRACE SD_ID128_MAKE(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95) +#define SD_MESSAGE_BACKTRACE_STR SD_ID128_MAKE_STR(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95) + +#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66) +#define SD_MESSAGE_SESSION_START_STR SD_ID128_MAKE_STR(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66) +#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a) +#define SD_MESSAGE_SESSION_STOP_STR SD_ID128_MAKE_STR(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a) +#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b) +#define SD_MESSAGE_SEAT_START_STR SD_ID128_MAKE_STR(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b) +#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5) +#define SD_MESSAGE_SEAT_STOP_STR SD_ID128_MAKE_STR(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5) +#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2) +#define SD_MESSAGE_MACHINE_START_STR SD_ID128_MAKE_STR(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2) +#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58) +#define SD_MESSAGE_MACHINE_STOP_STR SD_ID128_MAKE_STR(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58) + +#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27) +#define SD_MESSAGE_TIME_CHANGE_STR SD_ID128_MAKE_STR(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27) +#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90) +#define SD_MESSAGE_TIMEZONE_CHANGE_STR SD_ID128_MAKE_STR(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90) + +#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff) +#define SD_MESSAGE_STARTUP_FINISHED_STR SD_ID128_MAKE_STR(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff) +#define SD_MESSAGE_USER_STARTUP_FINISHED \ + SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1) +#define SD_MESSAGE_USER_STARTUP_FINISHED_STR \ + SD_ID128_MAKE_STR(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1) + +#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28) +#define SD_MESSAGE_SLEEP_START_STR SD_ID128_MAKE_STR(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28) +#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14) +#define SD_MESSAGE_SLEEP_STOP_STR SD_ID128_MAKE_STR(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14) + +#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40) +#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40) + +#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5) +#define SD_MESSAGE_UNIT_STARTING_STR SD_ID128_MAKE_STR(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5) +#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf) +#define SD_MESSAGE_UNIT_STARTED_STR SD_ID128_MAKE_STR(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf) +#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f) +#define SD_MESSAGE_UNIT_STOPPING_STR SD_ID128_MAKE_STR(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f) +#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86) +#define SD_MESSAGE_UNIT_STOPPED_STR SD_ID128_MAKE_STR(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86) +#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d) +#define SD_MESSAGE_UNIT_FAILED_STR SD_ID128_MAKE_STR(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d) +#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25) +#define SD_MESSAGE_UNIT_RELOADING_STR SD_ID128_MAKE_STR(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25) +#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54) +#define SD_MESSAGE_UNIT_RELOADED_STR SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54) + +#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7) +#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7) + +#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e) +#define SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR \ + SD_ID128_MAKE_STR(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e) + +#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7) +#define SD_MESSAGE_OVERMOUNTING_STR SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7) + +#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f) +#define SD_MESSAGE_LID_OPENED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f) +#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70) +#define SD_MESSAGE_LID_CLOSED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70) +#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff) +#define SD_MESSAGE_SYSTEM_DOCKED_STR SD_ID128_MAKE_STR(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff) +#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53) +#define SD_MESSAGE_SYSTEM_UNDOCKED_STR SD_ID128_MAKE_STR(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53) +#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71) +#define SD_MESSAGE_POWER_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71) +#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72) +#define SD_MESSAGE_SUSPEND_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72) +#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73) +#define SD_MESSAGE_HIBERNATE_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73) + +#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01) +#define SD_MESSAGE_INVALID_CONFIGURATION_STR \ + SD_ID128_MAKE_STR(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01) + +#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d) +#define SD_MESSAGE_DNSSEC_FAILURE_STR SD_ID128_MAKE_STR(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d) +#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED \ + SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65) +#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR \ + SD_ID128_MAKE_STR(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65) +#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57) +#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57) _SD_END_DECLARATIONS; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 17b966eb52..4a0a49f2bb 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -211,7 +211,7 @@ static int make_backup(const char *target, const char *x) { if (r < 0) return r; - r = copy_bytes(src, fileno(dst), (uint64_t) -1, true); + r = copy_bytes(src, fileno(dst), (uint64_t) -1, COPY_REFLINK); if (r < 0) goto fail; diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 630587aaf1..b42088c680 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -27,6 +27,7 @@ #include "unit.h" static int test_cgroup_mask(void) { + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; Manager *m = NULL; Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep; FILE *serial = NULL; @@ -34,7 +35,8 @@ static int test_cgroup_mask(void) { int r; /* Prepare the manager. */ - assert_se(set_unit_path(TEST_DATA_DIR("")) >= 0); + assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); r = manager_new(UNIT_FILE_USER, true, &m); if (r == -EPERM || r == -EACCES) { puts("manager_new: Permission denied. Skipping test."); @@ -110,10 +112,8 @@ static int test_cgroup_mask(void) { } int main(int argc, char* argv[]) { - _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int rc = 0; - assert_se(runtime_dir = setup_fake_runtime_dir()); TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); return rc; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index e65516f080..ed6725611d 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -31,6 +31,7 @@ #include "rm-rf.h" #include "string-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" static void test_copy_file(void) { @@ -52,7 +53,7 @@ static void test_copy_file(void) { assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0); - assert_se(copy_file(fn, fn_copy, 0, 0644, 0) == 0); + assert_se(copy_file(fn, fn_copy, 0, 0644, 0, COPY_REFLINK) == 0); assert_se(read_full_file(fn_copy, &buf, &sz) == 0); assert_se(streq(buf, "foo bar bar bar foo\n")); @@ -77,8 +78,8 @@ static void test_copy_file_fd(void) { assert_se(out_fd >= 0); assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0); - assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, true) < 0); - assert_se(copy_file_fd(in_fn, out_fd, true) >= 0); + assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, COPY_REFLINK) < 0); + assert_se(copy_file_fd(in_fn, out_fd, COPY_REFLINK) >= 0); assert_se(lseek(out_fd, SEEK_SET, 0) == 0); assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1); @@ -125,7 +126,7 @@ static void test_copy_tree(void) { unixsockp = strjoina(original_dir, "unixsock"); assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0); - assert_se(copy_tree(original_dir, copy_dir, true) == 0); + assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE) == 0); STRV_FOREACH(p, files) { _cleanup_free_ char *buf = NULL, *f; @@ -152,8 +153,8 @@ static void test_copy_tree(void) { assert_se(stat(unixsockp, &st) >= 0); assert_se(S_ISSOCK(st.st_mode)); - assert_se(copy_tree(original_dir, copy_dir, false) < 0); - assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0); + assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0); + assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0); (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); @@ -172,7 +173,7 @@ static void test_copy_bytes(void) { assert_se(pipe2(pipefd, O_CLOEXEC) == 0); - r = copy_bytes(infd, pipefd[1], (uint64_t) -1, false); + r = copy_bytes(infd, pipefd[1], (uint64_t) -1, 0); assert_se(r == 0); r = read(pipefd[0], buf, sizeof(buf)); @@ -185,13 +186,13 @@ static void test_copy_bytes(void) { assert_se(strneq(buf, buf2, r)); /* test copy_bytes with invalid descriptors */ - r = copy_bytes(pipefd[0], pipefd[0], 1, false); + r = copy_bytes(pipefd[0], pipefd[0], 1, 0); assert_se(r == -EBADF); - r = copy_bytes(pipefd[1], pipefd[1], 1, false); + r = copy_bytes(pipefd[1], pipefd[1], 1, 0); assert_se(r == -EBADF); - r = copy_bytes(pipefd[1], infd, 1, false); + r = copy_bytes(pipefd[1], infd, 1, 0); assert_se(r == -EBADF); } @@ -213,7 +214,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint fd3 = mkostemp_safe(fn3); assert_se(fd3 >= 0); - r = copy_bytes(fd, fd2, max_bytes, try_reflink); + r = copy_bytes(fd, fd2, max_bytes, try_reflink ? COPY_REFLINK : 0); if (max_bytes == (uint64_t) -1) assert_se(r == 0); else @@ -221,7 +222,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint assert_se(lseek(fd2, 0, SEEK_SET) == 0); - r = copy_bytes(fd2, fd3, max_bytes, try_reflink); + r = copy_bytes(fd2, fd3, max_bytes, try_reflink ? COPY_REFLINK : 0); if (max_bytes == (uint64_t) -1) assert_se(r == 0); else diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 3ec2dfe10e..8133343fb3 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -37,10 +37,9 @@ int main(int argc, char *argv[]) { Job *j; int r; - assert_se(runtime_dir = setup_fake_runtime_dir()); - /* prepare the test */ - assert_se(set_unit_path(TEST_DATA_DIR("")) >= 0); + assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); r = manager_new(UNIT_FILE_USER, true, &m); if (MANAGER_SKIP_TEST(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 145aa37a66..90540b884b 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -35,6 +35,7 @@ #endif #include "stat-util.h" #include "test-helper.h" +#include "tests.h" #include "unit.h" #include "util.h" #include "virt.h" @@ -516,7 +517,7 @@ int main(int argc, char *argv[]) { } assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); - assert_se(set_unit_path(TEST_DATA_DIR("/test-execute/")) >= 0); + assert_se(set_unit_path(get_testdata_dir("/test-execute")) >= 0); /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test * cases, otherwise (and if they are present in the environment), diff --git a/src/test/test-helper.h b/src/test/test-helper.h index 4e633ae6d8..ddb10f88fd 100644 --- a/src/test/test-helper.h +++ b/src/test/test-helper.h @@ -20,8 +20,6 @@ ***/ #include "sd-daemon.h" -#include "string-util.h" -#include "tests.h" #include "macro.h" @@ -41,6 +39,3 @@ -ENOENT, \ -ENOMEDIUM /* cannot determine cgroup */ \ ) - -#define TEST_DATA_DIR(subdir) \ - strjoina(getenv("TEST_DIR") ?: get_exe_relative_testdata_dir(), subdir) diff --git a/src/test/test-journal-importer.c b/src/test/test-journal-importer.c new file mode 100644 index 0000000000..a61212ce7b --- /dev/null +++ b/src/test/test-journal-importer.c @@ -0,0 +1,90 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "log.h" +#include "journal-importer.h" +#include "string-util.h" +#include "tests.h" + +static void assert_iovec_entry(const struct iovec *iovec, const char* content) { + assert_se(strlen(content) == iovec->iov_len); + assert_se(memcmp(content, iovec->iov_base, iovec->iov_len) == 0); +} + +#define COREDUMP_PROC_GROUP \ + "COREDUMP_PROC_CGROUP=1:name=systemd:/\n" \ + "0::/user.slice/user-1002.slice/user@1002.service/gnome-terminal-server.service\n" + +static void test_basic_parsing(void) { + _cleanup_(journal_importer_cleanup) JournalImporter imp = {}; + int r; + + imp.fd = open(get_testdata_dir("/journal-data/journal-1.txt"), O_RDONLY|O_CLOEXEC); + assert_se(imp.fd >= 0); + + do + r = journal_importer_process_data(&imp); + while (r == 0 && !journal_importer_eof(&imp)); + assert_se(r == 1); + + /* We read one entry, so we should get EOF on next read, but not yet */ + assert_se(!journal_importer_eof(&imp)); + + assert_se(imp.iovw.count == 6); + assert_iovec_entry(&imp.iovw.iovec[0], "_BOOT_ID=1531fd22ec84429e85ae888b12fadb91"); + assert_iovec_entry(&imp.iovw.iovec[1], "_TRANSPORT=journal"); + assert_iovec_entry(&imp.iovw.iovec[2], COREDUMP_PROC_GROUP); + assert_iovec_entry(&imp.iovw.iovec[3], "COREDUMP_RLIMIT=-1"); + assert_iovec_entry(&imp.iovw.iovec[4], COREDUMP_PROC_GROUP); + assert_iovec_entry(&imp.iovw.iovec[5], "_SOURCE_REALTIME_TIMESTAMP=1478389147837945"); + + /* Let's check if we get EOF now */ + r = journal_importer_process_data(&imp); + assert_se(r == 0); + assert_se(journal_importer_eof(&imp)); +} + +static void test_bad_input(void) { + _cleanup_(journal_importer_cleanup) JournalImporter imp = {}; + int r; + + imp.fd = open(get_testdata_dir("/journal-data/journal-2.txt"), O_RDONLY|O_CLOEXEC); + assert_se(imp.fd >= 0); + + do + r = journal_importer_process_data(&imp); + while (!journal_importer_eof(&imp)); + assert_se(r == 0); /* If we don't have enough input, 0 is returned */ + + assert_se(journal_importer_eof(&imp)); +} + +int main(int argc, char **argv) { + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_basic_parsing(); + test_bad_input(); + + return 0; +} diff --git a/src/test/test-path.c b/src/test/test-path.c index d09df3e8a5..70ac6b3df3 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -262,8 +262,8 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); + assert_se(set_unit_path(get_testdata_dir("/test-path")) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(set_unit_path(TEST_DATA_DIR("/test-path/")) >= 0); for (test = tests; test && *test; test++) { int r; diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index dab64fea57..81d9abc2d5 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -34,10 +34,9 @@ int main(int argc, char *argv[]) { FDSet *fdset = NULL; int r; - assert_se(runtime_dir = setup_fake_runtime_dir()); - /* prepare the test */ - assert_se(set_unit_path(TEST_DATA_DIR("")) >= 0); + assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); r = manager_new(UNIT_FILE_USER, true, &m); if (MANAGER_SKIP_TEST(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 490929e93b..1061b094d3 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -413,7 +413,7 @@ static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error * } log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE), + "MESSAGE_ID=" SD_MESSAGE_TIMEZONE_CHANGE_STR, "TIMEZONE=%s", c->zone, LOG_MESSAGE("Changed time zone to '%s'.", c->zone), NULL); @@ -591,7 +591,7 @@ static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *erro clock_set_hwclock(tm); log_struct(LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), + "MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR, "REALTIME="USEC_FMT, timespec_load(&ts), LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)), NULL); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index c4f4d46ca1..08a138b1b2 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1170,7 +1170,7 @@ static int create_item(Item *i) { return log_error_errno(r, "Failed to substitute specifiers in copy source %s: %m", i->argument); log_debug("Copying tree \"%s\" to \"%s\".", resolved, i->path); - r = copy_tree(resolved, i->path, false); + r = copy_tree(resolved, i->path, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID, COPY_REFLINK); if (r == -EROFS && stat(i->path, &st) == 0) r = -EEXIST; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 5be158f527..b5a88c667c 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -34,7 +34,8 @@ * * Type of names: * b<number> — BCMA bus core number - * c<bus_id> — CCW bus group name, without leading zeros [s390] + * c<bus_id> — bus id of a grouped CCW or CCW device, + * with all leading zeros stripped [s390] * o<index>[n<phys_port_name>|d<dev_port>] * — on-board device index number * s<slot>[f<function>][n<phys_port_name>|d<dev_port>] @@ -87,6 +88,11 @@ * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2 * ID_NET_NAME_MAC=enxd626b3450fb5 * ID_NET_NAME_PATH=enp0s29u1u2 + * + * s390 grouped CCW interface: + * /sys/devices/css0/0.0.0007/0.0.f5f0/group_device/net/encf5f0 + * ID_NET_NAME_MAC=enx026d3c00000a + * ID_NET_NAME_PATH=encf5f0 */ #include <errno.h> @@ -115,7 +121,7 @@ enum netname_type{ NET_USB, NET_BCMA, NET_VIRTIO, - NET_CCWGROUP, + NET_CCW, }; struct netnames { @@ -132,9 +138,21 @@ struct netnames { char usb_ports[IFNAMSIZ]; char bcma_core[IFNAMSIZ]; - char ccw_group[IFNAMSIZ]; + char ccw_busid[IFNAMSIZ]; }; +/* skip intermediate virtio devices */ +static struct udev_device *skip_virtio(struct udev_device *dev) { + struct udev_device *parent = dev; + + /* there can only ever be one virtio bus per parent device, so we can + safely ignore any virtio buses. see + <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */ + while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent))) + parent = udev_device_get_parent(parent); + return parent; +} + /* retrieve on-board index number and label from firmware */ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { unsigned dev_port = 0; @@ -308,12 +326,8 @@ static int names_pci(struct udev_device *dev, struct netnames *names) { assert(names); parent = udev_device_get_parent(dev); - - /* there can only ever be one virtio bus per parent device, so we can - safely ignore any virtio buses. see - <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */ - while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent))) - parent = udev_device_get_parent(parent); + /* skip virtio subsystem if present */ + parent = skip_virtio(parent); if (!parent) return -ENOENT; @@ -414,21 +428,26 @@ static int names_ccw(struct udev_device *dev, struct netnames *names) { struct udev_device *cdev; const char *bus_id; size_t bus_id_len; + size_t bus_id_start; int rc; + char *subsys; assert(dev); assert(names); /* Retrieve the associated CCW device */ cdev = udev_device_get_parent(dev); + /* skip virtio subsystem if present */ + cdev = skip_virtio(cdev); if (!cdev) return -ENOENT; - /* Network devices are always grouped CCW devices */ - if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev))) + /* Network devices are either single or grouped CCW devices */ + subsys = udev_device_get_subsystem(cdev); + if (!STRPTR_IN_SET(subsys, "ccwgroup", "ccw")) return -ENOENT; - /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely + /* Retrieve bus-ID of the CCW device. The bus-ID uniquely * identifies the network device on the Linux on System z channel * subsystem. Note that the bus-ID contains lowercase characters. */ @@ -447,14 +466,15 @@ static int names_ccw(struct udev_device *dev, struct netnames *names) { /* Strip leading zeros from the bus id for aesthetic purposes. This * keeps the ccw names stable, yet much shorter in general case of * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is - * not prepended when it is zero. + * not prepended when it is zero. Preserve the last 0 for 0.0.0000. */ - bus_id += strspn(bus_id, ".0"); + bus_id_start = strspn(bus_id, ".0"); + bus_id += bus_id_start < bus_id_len ? bus_id_start : bus_id_len - 1; /* Store the CCW bus-ID for use as network device name */ - rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "c%s", bus_id); - if (rc >= 0 && rc < (int)sizeof(names->ccw_group)) - names->type = NET_CCWGROUP; + rc = snprintf(names->ccw_busid, sizeof(names->ccw_busid), "c%s", bus_id); + if (rc >= 0 && rc < (int)sizeof(names->ccw_busid)) + names->type = NET_CCW; return 0; } @@ -564,10 +584,10 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool /* get path names for Linux on System z network devices */ err = names_ccw(dev, &names); - if (err >= 0 && names.type == NET_CCWGROUP) { + if (err >= 0 && names.type == NET_CCW) { char str[IFNAMSIZ]; - if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str)) + if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_busid) < (int)sizeof(str)) udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); goto out; } |