This file is part of systemd.
Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <stdio.h>
+#include <stdio_ext.h>
#include <sys/prctl.h>
#include <sys/xattr.h>
#include <unistd.h>
CONTEXT_SIGNAL,
CONTEXT_TIMESTAMP,
CONTEXT_RLIMIT,
+ CONTEXT_HOSTNAME,
CONTEXT_COMM,
CONTEXT_EXE,
CONTEXT_UNIT,
}
static inline uint64_t storage_size_max(void) {
- return arg_storage == COREDUMP_STORAGE_EXTERNAL ? arg_external_size_max : arg_journal_size_max;
+ if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
+ return arg_external_size_max;
+ if (arg_storage == COREDUMP_STORAGE_JOURNAL)
+ return arg_journal_size_max;
+ assert(arg_storage == COREDUMP_STORAGE_NONE);
+ return 0;
}
static int fix_acl(int fd, uid_t uid) {
assert(fd >= 0);
- if (uid <= SYSTEM_UID_MAX)
+ if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
return 0;
/* Make sure normal users can read (but not write or delete)
[CONTEXT_SIGNAL] = "user.coredump.signal",
[CONTEXT_TIMESTAMP] = "user.coredump.timestamp",
[CONTEXT_RLIMIT] = "user.coredump.rlimit",
+ [CONTEXT_HOSTNAME] = "user.coredump.hostname",
[CONTEXT_COMM] = "user.coredump.comm",
[CONTEXT_EXE] = "user.coredump.exe",
};
if (fsync(fd) < 0)
return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
+ (void) fsync_directory_of_file(fd);
+
r = link_tmpfile(fd, filename, target);
if (r < 0)
return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
_cleanup_free_ char *fn = NULL, *tmp = NULL;
_cleanup_close_ int fd = -1;
- uint64_t rlimit, max_size;
+ uint64_t rlimit, process_limit, max_size;
struct stat st;
uid_t uid;
int r;
return -EBADSLT;
}
+ process_limit = MAX(arg_process_size_max, storage_size_max());
+ if (process_limit == 0) {
+ log_debug("Limits for coredump processing and storage are both 0, not dumping core.");
+ return -EBADSLT;
+ }
+
/* Never store more than the process configured, or than we actually shall keep or process */
- max_size = MIN(rlimit, MAX(arg_process_size_max, storage_size_max()));
+ max_size = MIN(rlimit, process_limit);
r = make_filename(context, &fn);
if (r < 0)
log_struct(LOG_INFO,
LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size),
"SIZE_LIMIT=%zu", max_size,
- "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR,
- NULL);
+ "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR);
if (fstat(fd, &st) < 0) {
log_error_errno(errno, "Failed to fstat core file %s: %m", coredump_tmpfile_name(tmp));
if (tmp)
unlink_noerrno(tmp);
- *ret_filename = fn_compressed; /* compressed */
- *ret_node_fd = fd_compressed; /* compressed */
- *ret_data_fd = fd; /* uncompressed */
+ *ret_filename = TAKE_PTR(fn_compressed); /* compressed */
+ *ret_node_fd = TAKE_FD(fd_compressed); /* compressed */
+ *ret_data_fd = TAKE_FD(fd); /* uncompressed */
*ret_size = (uint64_t) st.st_size; /* uncompressed */
- fn_compressed = NULL;
- fd = fd_compressed = -1;
-
return 0;
fail_compressed:
if (r < 0)
goto fail;
- *ret_filename = fn;
- *ret_data_fd = fd;
+ *ret_filename = TAKE_PTR(fn);
+ *ret_data_fd = TAKE_FD(fd);
*ret_node_fd = -1;
*ret_size = (uint64_t) st.st_size;
- fn = NULL;
- fd = -1;
-
return 0;
fail:
return -EIO;
}
- *ret = field;
+ *ret = TAKE_PTR(field);
*ret_size = size + 9;
- field = NULL;
-
return 0;
}
if (!stream)
return -ENOMEM;
+ (void) __fsetlocking(stream, FSETLOCKING_BYCALLER);
+
FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
_cleanup_fclose_ FILE *fdinfo = NULL;
_cleanup_free_ char *fdname = NULL;
continue;
fdinfo = fdopen(fd, "re");
- if (fdinfo == NULL) {
- close(fd);
+ if (!fdinfo) {
+ safe_close(fd);
continue;
}
FOREACH_LINE(line, fdinfo, break) {
- fputs_unlocked(line, stream);
+ fputs(line, stream);
if (!endswith(line, "\n"))
fputc('\n', stream);
}
if (errno > 0)
return -errno;
- *open_fds = buffer;
- buffer = NULL;
+ *open_fds = TAKE_PTR(buffer);
return 0;
}
[CONTEXT_SIGNAL] = "COREDUMP_SIGNAL=",
[CONTEXT_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
[CONTEXT_RLIMIT] = "COREDUMP_RLIMIT=",
+ [CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=",
[CONTEXT_COMM] = "COREDUMP_COMM=",
[CONTEXT_EXE] = "COREDUMP_EXE=",
};
assert(context);
for (i = 0; i < ELEMENTSOF(context_field_names); i++) {
- size_t l;
+ char *p;
if (!context_field_names[i])
continue;
- l = strlen(context_field_names[i]);
- if (iovec->iov_len < l)
- continue;
-
- if (memcmp(iovec->iov_base, context_field_names[i], l) != 0)
+ p = memory_startswith(iovec->iov_base, iovec->iov_len, context_field_names[i]);
+ if (!p)
continue;
/* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
* buffer, though not included in the iov_len count. (see below) */
- context[i] = (char*) iovec->iov_base + l;
+ context[i] = p;
break;
}
}
assert(context[CONTEXT_SIGNAL]);
assert(context[CONTEXT_TIMESTAMP]);
assert(context[CONTEXT_RLIMIT]);
+ assert(context[CONTEXT_HOSTNAME]);
assert(context[CONTEXT_COMM]);
assert(coredump_fd >= 0);
return 0;
}
-static char* set_iovec_field(struct iovec iovec[27], size_t *n_iovec, const char *field, const char *value) {
+static char* set_iovec_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
char *x;
x = strappend(field, value);
return x;
}
-static char* set_iovec_field_free(struct iovec iovec[27], size_t *n_iovec, const char *field, char *value) {
+static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
char *x;
x = set_iovec_field(iovec, n_iovec, field, value);
char **comm_fallback,
struct iovec *iovec, size_t *n_iovec) {
- /* We need 26 empty slots in iovec!
+ /* We need 27 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.) */
/* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */
if (is_pid1_crash((const char**) context)) {
log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
- (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
+ disable_coredumps();
}
set_iovec_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
return log_oom();
+ if (!set_iovec_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
+ return log_oom();
+
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
return log_oom();
static int process_kernel(int argc, char* argv[]) {
char* context[_CONTEXT_MAX] = {};
- struct iovec iovec[28 + SUBMIT_COREDUMP_FIELDS];
+ struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
size_t i, n_iovec, n_to_free = 0;
int r;
context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL];
context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT];
+ context[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME];
r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
if (r < 0)
context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL];
context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT];
+ context[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME];
- n_allocated = 33 + COREDUMP_STORAGE_EXTERNAL;
- /* 25 metadata, 2 static, +unknown input, 4 storage, rounded up */
+ n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL;
+ /* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */
iovec = new(struct iovec, n_allocated);
if (!iovec)
return log_oom();