mirror of
https://github.com/systemd/systemd.git
synced 2025-01-17 06:04:07 +03:00
Merge pull request #2555 from poettering/coredump-fixes
Coredump fixes and more
This commit is contained in:
commit
059adb5ac0
33
Makefile.am
33
Makefile.am
@ -4397,30 +4397,39 @@ systemd_socket_proxyd_LDADD = \
|
||||
# ------------------------------------------------------------------------------
|
||||
if ENABLE_COREDUMP
|
||||
systemd_coredump_SOURCES = \
|
||||
src/journal/coredump.c \
|
||||
src/journal/coredump-vacuum.c \
|
||||
src/journal/coredump-vacuum.h
|
||||
src/coredump/coredump.c \
|
||||
src/coredump/coredump-vacuum.c \
|
||||
src/coredump/coredump-vacuum.h
|
||||
|
||||
systemd_coredump_LDADD = \
|
||||
libshared.la
|
||||
|
||||
if HAVE_ELFUTILS
|
||||
systemd_coredump_SOURCES += \
|
||||
src/journal/stacktrace.c \
|
||||
src/journal/stacktrace.h
|
||||
src/coredump/stacktrace.c \
|
||||
src/coredump/stacktrace.h
|
||||
|
||||
systemd_coredump_LDADD += \
|
||||
$(ELFUTILS_LIBS)
|
||||
endif
|
||||
|
||||
nodist_systemunit_DATA += \
|
||||
units/systemd-coredump@.service
|
||||
|
||||
dist_systemunit_DATA += \
|
||||
units/systemd-coredump.socket
|
||||
|
||||
SOCKETS_TARGET_WANTS += \
|
||||
systemd-coredump.socket
|
||||
|
||||
rootlibexec_PROGRAMS += \
|
||||
systemd-coredump
|
||||
|
||||
dist_pkgsysconf_DATA += \
|
||||
src/journal/coredump.conf
|
||||
src/coredump/coredump.conf
|
||||
|
||||
coredumpctl_SOURCES = \
|
||||
src/journal/coredumpctl.c
|
||||
src/coredump/coredumpctl.c
|
||||
|
||||
coredumpctl_LDADD = \
|
||||
libshared.la
|
||||
@ -4432,9 +4441,9 @@ manual_tests += \
|
||||
test-coredump-vacuum
|
||||
|
||||
test_coredump_vacuum_SOURCES = \
|
||||
src/journal/test-coredump-vacuum.c \
|
||||
src/journal/coredump-vacuum.c \
|
||||
src/journal/coredump-vacuum.h
|
||||
src/coredump/test-coredump-vacuum.c \
|
||||
src/coredump/coredump-vacuum.c \
|
||||
src/coredump/coredump-vacuum.h
|
||||
|
||||
test_coredump_vacuum_LDADD = \
|
||||
libshared.la
|
||||
@ -4453,7 +4462,8 @@ CLEANFILES += \
|
||||
endif
|
||||
|
||||
EXTRA_DIST += \
|
||||
sysctl.d/50-coredump.conf.in
|
||||
sysctl.d/50-coredump.conf.in \
|
||||
units/systemd-coredump@.service.in
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
if ENABLE_BINFMT
|
||||
@ -4860,7 +4870,6 @@ nodist_systemunit_DATA += \
|
||||
GENERAL_ALIASES += \
|
||||
$(systemunitdir)/systemd-timesyncd.service $(pkgsysconfdir)/system/sysinit.target.wants/systemd-timesyncd.service
|
||||
|
||||
|
||||
nodist_pkgsysconf_DATA += \
|
||||
src/timesync/timesyncd.conf
|
||||
|
||||
|
33
NEWS
33
NEWS
@ -26,6 +26,39 @@ CHANGES WITH 229:
|
||||
* /dev/disk/by-path/ symlink support has been (re-)added for virtio
|
||||
devices.
|
||||
|
||||
* The coredump collection logic has been reworked: when a coredump is
|
||||
collected it is now written to disk, compressed and processed
|
||||
(including stacktrace extraction) from a new instantiated service
|
||||
systemd-coredump@.service, instead of directly from the
|
||||
/proc/sys/kernel/core_pattern hook we provide. This is beneficial as
|
||||
processing large coredumps can take up a substantial amount of
|
||||
resources and time, and this previously happened entirely outside of
|
||||
systemd's service supervision. With the new logic the core_pattern
|
||||
hook only does minimal metadata collection before passing off control
|
||||
to the new instantiated service, which is configured with a time
|
||||
limit, a nice level and other settings to minimize negative impact on
|
||||
the rest of the system. Also note that the new logic will honour the
|
||||
RLIMIT_CORE setting of the crashed process, which now allows users
|
||||
and processes to turn off coredumping for their processes by setting
|
||||
this limit.
|
||||
|
||||
* The RLIMIT_CORE resource limit now defaults to "unlimited" for PID 1
|
||||
and all forked processes by default. Previously, PID 1 would leave
|
||||
the setting at "0" for all processes, as set by the kernel. Note that
|
||||
the resource limit traditionally has no effect on the generated
|
||||
coredumps on the system if the /proc/sys/kernel/core_pattern hook
|
||||
logic is used. Since the limit is now honoured (see above) its
|
||||
default has been changed so that the coredumping logic is enabled by
|
||||
default for all processes, while allowing specific opt-out.
|
||||
|
||||
* When the stacktrace is extracted from processes of system users, this
|
||||
is now done as "systemd-coredump" user, in order to sandbox this
|
||||
potentially security sensitive parsing operation. (Note that when
|
||||
processing coredumps of normal users this is done under the user ID
|
||||
of process that crashed, as before.) Packagers should take notice
|
||||
that it is now necessary to create the "systemd-coredump" system user
|
||||
and group at package installation time.
|
||||
|
||||
* The systemd-activate socket activation testing tool gained support
|
||||
for SOCK_DGRAM and SOCK_SEQPACKET sockets using the new --datagram
|
||||
and --seqpacket switches. It also has been extended to support both
|
||||
|
3
README
3
README
@ -203,6 +203,9 @@ USERS AND GROUPS:
|
||||
Similarly, the kdbus dbus1 proxy daemon requires the
|
||||
"systemd-bus-proxy" system user and group to exist.
|
||||
|
||||
Similarly, the coredump support requires the
|
||||
"systemd-coredump" system user and group to exist.
|
||||
|
||||
NSS:
|
||||
systemd ships with three NSS modules:
|
||||
|
||||
|
11
TODO
11
TODO
@ -33,8 +33,6 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* rework coredump tool to move actual processing into a socket activated service
|
||||
|
||||
* cache sd_event_now() result from before the first iteration...
|
||||
|
||||
* remove Capabilities=, after all AmbientCapabilities= and CapabilityBoundingSet= should be enough.
|
||||
@ -43,11 +41,6 @@ Features:
|
||||
|
||||
* add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction
|
||||
|
||||
* coredump logic should use prlimit() to query RLIMIT_CORE of the dumpee and honour it
|
||||
|
||||
* Add a MaxRuntimeSec= setting for service units (or units in general) to terminate units after they ran for a certain
|
||||
amount of time
|
||||
|
||||
* Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC?
|
||||
|
||||
* PID1: find a way how we can reload unit file configuration for
|
||||
@ -649,10 +642,6 @@ Features:
|
||||
* coredump:
|
||||
- save coredump in Windows/Mozilla minidump format
|
||||
- move PID 1 segfaults to /var/lib/systemd/coredump?
|
||||
- make the handler check /proc/$PID/rlimits for RLIMIT_CORE,
|
||||
and supress coredump if turned off. Then change RLIMIT_CORE to
|
||||
infinity by default for all services. This then allows per-service
|
||||
control of coredumping.
|
||||
|
||||
* support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting)
|
||||
|
||||
|
@ -1106,6 +1106,7 @@ have_coredump=no
|
||||
AC_ARG_ENABLE(coredump, AS_HELP_STRING([--disable-coredump], [disable coredump hook]))
|
||||
if test "x$enable_coredump" != "xno"; then
|
||||
have_coredump=yes
|
||||
M4_DEFINES="$M4_DEFINES -DENABLE_COREDUMP"
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_COREDUMP, [test "$have_coredump" = "yes"])
|
||||
|
||||
|
@ -60,27 +60,21 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-activate</command> can be used to
|
||||
launch a socket-activated daemon from the command line for
|
||||
testing purposes. It can also be used to launch single instances
|
||||
of the daemon per connection (inetd-style).
|
||||
<para><command>systemd-activate</command> may be used to launch a socket-activated service binary from the command
|
||||
line for testing purposes. It may also be used to launch individual instances of the service binary per connection.
|
||||
</para>
|
||||
|
||||
<para>The daemon to launch and its options should be specified
|
||||
after options intended for <command>systemd-activate</command>.
|
||||
</para>
|
||||
|
||||
<para>If the <option>-a</option> option is given, file descriptor
|
||||
of the connection will be used as the standard input and output of
|
||||
the launched process. Otherwise, standard input and output will be
|
||||
inherited, and sockets will be passed through file descriptors 3
|
||||
and higher. Sockets passed through <varname>$LISTEN_FDS</varname>
|
||||
to <command>systemd-activate</command> will be passed through to
|
||||
the daemon, in the original positions. Other sockets specified
|
||||
with <option>--listen</option> will use consecutive descriptors.
|
||||
By default, <command>systemd-activate</command> listens on a
|
||||
stream socket, use <option>--datagram</option> to listen on
|
||||
a datagram socket instead (see below).
|
||||
<para>If the <option>--inetd</option> option is given, the socket file descriptor will be used as the standard
|
||||
input and output of the launched process. Otherwise, standard input and output will be inherited, and sockets will
|
||||
be passed through file descriptors 3 and higher. Sockets passed through <varname>$LISTEN_FDS</varname> to
|
||||
<command>systemd-activate</command> will be passed through to the daemon, in the original positions. Other sockets
|
||||
specified with <option>--listen=</option> will use consecutive descriptors. By default,
|
||||
<command>systemd-activate</command> listens on a stream socket, use <option>--datagram</option> and
|
||||
<option>--seqpacket</option> to listen on datagram or sequential packet sockets instead (see below).
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@ -101,16 +95,32 @@
|
||||
<term><option>-a</option></term>
|
||||
<term><option>--accept</option></term>
|
||||
|
||||
<listitem><para>Launch a separate instance of daemon per
|
||||
connection and pass the connection socket as standard input
|
||||
and standard output.</para></listitem>
|
||||
<listitem><para>Launch an instance of the service binary for each connection and pass the connection
|
||||
socket.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-d</option></term>
|
||||
<term><option>--datagram</option></term>
|
||||
|
||||
<listitem><para>Listen on a datagram socket, instead of a stream socket.</para></listitem>
|
||||
<listitem><para>Listen on a datagram socket (<constant>SOCK_DGRAM</constant>), instead of a stream socket
|
||||
(<constant>SOCK_STREAM</constant>). May not be combined with <option>--seqpacket</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--seqpacket</option></term>
|
||||
|
||||
<listitem><para>Listen on a sequential packet socket (<constant>SOCK_SEQPACKET</constant>), instead of a stream
|
||||
socket (<constant>SOCK_STREAM</constant>). May not be combined with
|
||||
<option>--datagram</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--inetd</option></term>
|
||||
|
||||
<listitem><para>Use the inetd protocol for passing file descriptors, i.e. as standard input and standard
|
||||
output, instead of the new-style protocol for passing file descriptors using <varname>$LISTEN_FDS</varname>
|
||||
(see above).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -170,7 +180,7 @@
|
||||
<example>
|
||||
<title>Run an echo server on port 2000</title>
|
||||
|
||||
<programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 -a cat</programlisting>
|
||||
<programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 --inetd -a cat</programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
|
@ -728,20 +728,14 @@
|
||||
<term><varname>JobTimeoutAction=</varname></term>
|
||||
<term><varname>JobTimeoutRebootArgument=</varname></term>
|
||||
|
||||
<listitem><para>When a job for this unit is queued, a time-out
|
||||
may be configured. If this time limit is reached, the job will
|
||||
be cancelled, the unit however will not change state or even
|
||||
enter the <literal>failed</literal> mode. This value defaults
|
||||
to 0 (job timeouts disabled), except for device units. NB:
|
||||
this timeout is independent from any unit-specific timeout
|
||||
(for example, the timeout set with
|
||||
<varname>TimeoutStartSec=</varname> in service units) as the
|
||||
job timeout has no effect on the unit itself, only on the job
|
||||
that might be pending for it. Or in other words: unit-specific
|
||||
timeouts are useful to abort unit state changes, and revert
|
||||
them. The job timeout set with this option however is useful
|
||||
to abort only the job waiting for the unit state to
|
||||
change.</para>
|
||||
<listitem><para>When a job for this unit is queued, a time-out may be configured. If this time limit is
|
||||
reached, the job will be cancelled, the unit however will not change state or even enter the
|
||||
<literal>failed</literal> mode. This value defaults to <literal>infinity</literal> (job timeouts disabled),
|
||||
except for device units. NB: this timeout is independent from any unit-specific timeout (for example, the
|
||||
timeout set with <varname>TimeoutStartSec=</varname> in service units) as the job timeout has no effect on the
|
||||
unit itself, only on the job that might be pending for it. Or in other words: unit-specific timeouts are useful
|
||||
to abort unit state changes, and revert them. The job timeout set with this option however is useful to abort
|
||||
only the job waiting for the unit state to change.</para>
|
||||
|
||||
<para><varname>JobTimeoutAction=</varname>
|
||||
optionally configures an additional
|
||||
|
@ -37,10 +37,11 @@
|
||||
|
||||
static char** arg_listen = NULL;
|
||||
static bool arg_accept = false;
|
||||
static bool arg_datagram = false;
|
||||
static int arg_socket_type = SOCK_STREAM;
|
||||
static char** arg_args = NULL;
|
||||
static char** arg_setenv = NULL;
|
||||
static const char *arg_fdname = NULL;
|
||||
static bool arg_inetd = false;
|
||||
|
||||
static int add_epoll(int epoll_fd, int fd) {
|
||||
struct epoll_event ev = {
|
||||
@ -96,12 +97,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
|
||||
*/
|
||||
|
||||
STRV_FOREACH(address, arg_listen) {
|
||||
|
||||
if (arg_datagram)
|
||||
fd = make_socket_fd(LOG_DEBUG, *address, SOCK_DGRAM, SOCK_CLOEXEC);
|
||||
else
|
||||
fd = make_socket_fd(LOG_DEBUG, *address, SOCK_STREAM, (arg_accept*SOCK_CLOEXEC));
|
||||
|
||||
fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept*SOCK_CLOEXEC));
|
||||
if (fd < 0) {
|
||||
log_open();
|
||||
return log_error_errno(fd, "Failed to open '%s': %m", *address);
|
||||
@ -132,14 +128,20 @@ static int open_sockets(int *epoll_fd, bool accept) {
|
||||
return count;
|
||||
}
|
||||
|
||||
static int launch(char* name, char **argv, char **env, int fds) {
|
||||
static int exec_process(const char* name, char **argv, char **env, int start_fd, int n_fds) {
|
||||
|
||||
static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
|
||||
_cleanup_strv_free_ char **envp = NULL;
|
||||
_cleanup_free_ char *tmp = NULL;
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
unsigned n_env = 0, length;
|
||||
char **s;
|
||||
const char *tocopy;
|
||||
unsigned i;
|
||||
char **s;
|
||||
int r;
|
||||
|
||||
if (arg_inetd && n_fds != 1) {
|
||||
log_error("--inetd only supported for single file descriptors.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
length = strv_length(arg_setenv);
|
||||
|
||||
@ -149,6 +151,7 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
return log_oom();
|
||||
|
||||
STRV_FOREACH(s, arg_setenv) {
|
||||
|
||||
if (strchr(*s, '=')) {
|
||||
char *k;
|
||||
|
||||
@ -172,13 +175,15 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
envp[n_env] = strdup(n);
|
||||
if (!envp[n_env])
|
||||
return log_oom();
|
||||
|
||||
n_env ++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(tocopy); i++) {
|
||||
FOREACH_STRING(tocopy, "TERM=", "PATH=", "USER=", "HOME=") {
|
||||
const char *n;
|
||||
|
||||
n = strv_find_prefix(env, tocopy[i]);
|
||||
n = strv_find_prefix(env, tocopy);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
@ -189,8 +194,34 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
n_env ++;
|
||||
}
|
||||
|
||||
if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) ||
|
||||
(asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
|
||||
if (arg_inetd) {
|
||||
assert(n_fds == 1);
|
||||
|
||||
r = dup2(start_fd, STDIN_FILENO);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "Failed to dup connection to stdin: %m");
|
||||
|
||||
r = dup2(start_fd, STDOUT_FILENO);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "Failed to dup connection to stdout: %m");
|
||||
|
||||
start_fd = safe_close(start_fd);
|
||||
} else {
|
||||
if (start_fd != SD_LISTEN_FDS_START) {
|
||||
assert(n_fds == 1);
|
||||
|
||||
r = dup2(start_fd, SD_LISTEN_FDS_START);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "Failed to dup connection: %m");
|
||||
|
||||
safe_close(start_fd);
|
||||
start_fd = SD_LISTEN_FDS_START;
|
||||
}
|
||||
|
||||
if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%i", n_fds) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (arg_fdname) {
|
||||
@ -200,7 +231,7 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
if (!e)
|
||||
return log_oom();
|
||||
|
||||
for (i = 1; i < (unsigned) fds; i++) {
|
||||
for (i = 1; i < (unsigned) n_fds; i++) {
|
||||
char *c;
|
||||
|
||||
c = strjoin(e, ":", arg_fdname, NULL);
|
||||
@ -215,24 +246,24 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
|
||||
envp[n_env++] = e;
|
||||
}
|
||||
|
||||
tmp = strv_join(argv, " ");
|
||||
if (!tmp)
|
||||
return log_oom();
|
||||
|
||||
log_info("Execing %s (%s)", name, tmp);
|
||||
execvpe(name, argv, envp);
|
||||
|
||||
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
|
||||
}
|
||||
|
||||
static int launch1(const char* child, char** argv, char **env, int fd) {
|
||||
_cleanup_free_ char *tmp = NULL;
|
||||
pid_t parent_pid, child_pid;
|
||||
int r;
|
||||
joined = strv_join(argv, " ");
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
tmp = strv_join(argv, " ");
|
||||
if (!tmp)
|
||||
log_info("Execing %s (%s)", name, joined);
|
||||
execvpe(name, argv, envp);
|
||||
|
||||
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, joined);
|
||||
}
|
||||
|
||||
static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
pid_t parent_pid, child_pid;
|
||||
|
||||
joined = strv_join(argv, " ");
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
parent_pid = getpid();
|
||||
@ -247,24 +278,6 @@ static int launch1(const char* child, char** argv, char **env, int fd) {
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
r = dup2(fd, STDIN_FILENO);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to dup connection to stdin: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = dup2(fd, STDOUT_FILENO);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to dup connection to stdout: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = close(fd);
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to close dupped connection: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Make sure the child goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
@ -274,31 +287,27 @@ static int launch1(const char* child, char** argv, char **env, int fd) {
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
execvp(child, argv);
|
||||
log_error_errno(errno, "Failed to exec child %s: %m", child);
|
||||
exec_process(child, argv, env, fd, 1);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
|
||||
|
||||
log_info("Spawned %s (%s) as PID %d", child, joined, child_pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_accept(const char* name, char **argv, char **envp, int fd) {
|
||||
_cleanup_free_ char *local = NULL, *peer = NULL;
|
||||
_cleanup_close_ int fd2 = -1;
|
||||
_cleanup_close_ int fd_accepted = -1;
|
||||
|
||||
fd2 = accept(fd, NULL, NULL);
|
||||
if (fd2 < 0) {
|
||||
log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
|
||||
return fd2;
|
||||
}
|
||||
fd_accepted = accept4(fd, NULL, NULL, 0);
|
||||
if (fd_accepted < 0)
|
||||
return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
|
||||
|
||||
getsockname_pretty(fd2, &local);
|
||||
getpeername_pretty(fd2, true, &peer);
|
||||
getsockname_pretty(fd_accepted, &local);
|
||||
getpeername_pretty(fd_accepted, true, &peer);
|
||||
log_info("Connection from %s to %s", strna(peer), strna(local));
|
||||
|
||||
return launch1(name, argv, envp, fd2);
|
||||
return fork_and_exec_process(name, argv, envp, fd_accepted);
|
||||
}
|
||||
|
||||
/* SIGCHLD handler. */
|
||||
@ -306,21 +315,24 @@ static void sigchld_hdl(int sig, siginfo_t *t, void *data) {
|
||||
PROTECT_ERRNO;
|
||||
|
||||
log_info("Child %d died with code %d", t->si_pid, t->si_status);
|
||||
|
||||
/* Wait for a dead child. */
|
||||
waitpid(t->si_pid, NULL, 0);
|
||||
(void) waitpid(t->si_pid, NULL, 0);
|
||||
}
|
||||
|
||||
static int install_chld_handler(void) {
|
||||
int r;
|
||||
struct sigaction act = {
|
||||
static const struct sigaction act = {
|
||||
.sa_flags = SA_SIGINFO,
|
||||
.sa_sigaction = sigchld_hdl,
|
||||
};
|
||||
|
||||
int r;
|
||||
|
||||
r = sigaction(SIGCHLD, &act, 0);
|
||||
if (r < 0)
|
||||
log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
|
||||
return r;
|
||||
return log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void help(void) {
|
||||
@ -331,8 +343,10 @@ static void help(void) {
|
||||
" --version Print version string and exit\n"
|
||||
" -l --listen=ADDR Listen for raw connections at ADDR\n"
|
||||
" -d --datagram Listen on datagram instead of stream socket\n"
|
||||
" --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n"
|
||||
" -a --accept Spawn separate child for each connection\n"
|
||||
" -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
|
||||
" --inetd Enable inetd file descriptor passing protocol\n"
|
||||
"\n"
|
||||
"Note: file descriptors from sd_listen_fds() will be passed through.\n"
|
||||
, program_invocation_short_name);
|
||||
@ -342,17 +356,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_FDNAME,
|
||||
ARG_SEQPACKET,
|
||||
ARG_INETD,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "datagram", no_argument, NULL, 'd' },
|
||||
{ "seqpacket", no_argument, NULL, ARG_SEQPACKET },
|
||||
{ "listen", required_argument, NULL, 'l' },
|
||||
{ "accept", no_argument, NULL, 'a' },
|
||||
{ "setenv", required_argument, NULL, 'E' },
|
||||
{ "environment", required_argument, NULL, 'E' }, /* legacy alias */
|
||||
{ "fdname", required_argument, NULL, ARG_FDNAME },
|
||||
{ "inetd", no_argument, NULL, ARG_INETD },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -378,7 +396,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
arg_datagram = true;
|
||||
if (arg_socket_type == SOCK_SEQPACKET) {
|
||||
log_error("--datagram may not be combined with --seqpacket.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_socket_type = SOCK_DGRAM;
|
||||
break;
|
||||
|
||||
case ARG_SEQPACKET:
|
||||
if (arg_socket_type == SOCK_DGRAM) {
|
||||
log_error("--seqpacket may not be combined with --datagram.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_socket_type = SOCK_SEQPACKET;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
@ -401,6 +433,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_fdname = optarg;
|
||||
break;
|
||||
|
||||
case ARG_INETD:
|
||||
arg_inetd = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -414,7 +450,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_datagram && arg_accept) {
|
||||
if (arg_socket_type == SOCK_DGRAM && arg_accept) {
|
||||
log_error("Datagram sockets do not accept connections. "
|
||||
"The --datagram and --accept options may not be combined.");
|
||||
return -EINVAL;
|
||||
@ -462,15 +498,14 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
log_info("Communication attempt on fd %i.", event.data.fd);
|
||||
if (arg_accept) {
|
||||
r = do_accept(argv[optind], argv + optind, envp,
|
||||
event.data.fd);
|
||||
r = do_accept(argv[optind], argv + optind, envp, event.data.fd);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
launch(argv[optind], argv + optind, envp, n);
|
||||
exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START, n);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -871,14 +871,13 @@ int send_one_fd_sa(
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(int))];
|
||||
} control = {};
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
struct msghdr mh = {
|
||||
.msg_name = (struct sockaddr*) sa,
|
||||
.msg_namelen = len,
|
||||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
assert(transport_fd >= 0);
|
||||
assert(fd >= 0);
|
||||
|
@ -161,7 +161,7 @@ Unit.OnFailureJobMode, config_parse_job_mode, 0,
|
||||
Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode)
|
||||
Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate)
|
||||
Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0
|
||||
Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout)
|
||||
Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout)
|
||||
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
|
||||
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
|
||||
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
|
||||
@ -215,9 +215,9 @@ Service.ExecReload, config_parse_exec, SERVICE_EXE
|
||||
Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command)
|
||||
Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command)
|
||||
Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)
|
||||
Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
|
||||
Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
|
||||
Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
|
||||
Service.TimeoutSec, config_parse_service_timeout, 0, 0
|
||||
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
|
||||
Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
|
||||
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
|
||||
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
|
||||
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
|
||||
|
@ -1711,7 +1711,8 @@ int config_parse_bus_name(
|
||||
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
|
||||
}
|
||||
|
||||
int config_parse_service_timeout(const char *unit,
|
||||
int config_parse_service_timeout(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
@ -1723,6 +1724,7 @@ int config_parse_service_timeout(const char *unit,
|
||||
void *userdata) {
|
||||
|
||||
Service *s = userdata;
|
||||
usec_t usec;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
@ -1730,25 +1732,63 @@ int config_parse_service_timeout(const char *unit,
|
||||
assert(rvalue);
|
||||
assert(s);
|
||||
|
||||
r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
|
||||
rvalue, data, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
|
||||
|
||||
if (streq(lvalue, "TimeoutSec")) {
|
||||
s->start_timeout_defined = true;
|
||||
s->timeout_stop_usec = s->timeout_start_usec;
|
||||
} else if (streq(lvalue, "TimeoutStartSec"))
|
||||
s->start_timeout_defined = true;
|
||||
r = parse_sec(rvalue, &usec);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
|
||||
* immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
|
||||
* all other timeouts. */
|
||||
if (usec <= 0)
|
||||
usec = USEC_INFINITY;
|
||||
|
||||
if (s->timeout_start_usec <= 0)
|
||||
s->timeout_start_usec = USEC_INFINITY;
|
||||
if (s->timeout_stop_usec <= 0)
|
||||
s->timeout_stop_usec = USEC_INFINITY;
|
||||
if (!streq(lvalue, "TimeoutStopSec")) {
|
||||
s->start_timeout_defined = true;
|
||||
s->timeout_start_usec = usec;
|
||||
}
|
||||
|
||||
if (!streq(lvalue, "TimeoutStartSec"))
|
||||
s->timeout_stop_usec = usec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_sec_fix_0(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
usec_t *usec = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(usec);
|
||||
|
||||
/* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
|
||||
* compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
|
||||
* timeout. */
|
||||
|
||||
r = parse_sec(rvalue, usec);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*usec <= 0)
|
||||
*usec = USEC_INFINITY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ int config_parse_bus_name(const char* unit, const char *filename, unsigned line,
|
||||
int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_sec_fix_0(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
|
||||
|
@ -172,19 +172,15 @@ noreturn static void crash(int sig) {
|
||||
if (pid < 0)
|
||||
log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
|
||||
else if (pid == 0) {
|
||||
struct rlimit rl = {
|
||||
.rlim_cur = RLIM_INFINITY,
|
||||
.rlim_max = RLIM_INFINITY,
|
||||
};
|
||||
|
||||
/* Enable default signal handler for core dump */
|
||||
|
||||
sa = (struct sigaction) {
|
||||
.sa_handler = SIG_DFL,
|
||||
};
|
||||
(void) sigaction(sig, &sa, NULL);
|
||||
|
||||
/* Don't limit the coredump size */
|
||||
(void) setrlimit(RLIMIT_CORE, &rl);
|
||||
(void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
|
||||
|
||||
/* Just to be sure... */
|
||||
(void) chdir("/");
|
||||
@ -1466,6 +1462,17 @@ int main(int argc, char *argv[]) {
|
||||
kernel_timestamp = DUAL_TIMESTAMP_NULL;
|
||||
}
|
||||
|
||||
if (getpid() == 1) {
|
||||
/* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit)
|
||||
* will process core dumps for system services by default. */
|
||||
(void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
|
||||
|
||||
/* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored
|
||||
* until the systemd-coredump tool is enabled via sysctl. */
|
||||
if (!skip_setup)
|
||||
(void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
|
||||
}
|
||||
|
||||
/* Initialize default unit */
|
||||
r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
|
||||
if (r < 0) {
|
||||
|
1
src/coredump/Makefile
Symbolic link
1
src/coredump/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../Makefile
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,8 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define SD_RESOLVED_DNS (UINT64_C(1) << 0)
|
||||
#define SD_RESOLVED_LLMNR_IPV4 (UINT64_C(1) << 1)
|
||||
#define SD_RESOLVED_LLMNR_IPV6 (UINT64_C(1) << 2)
|
||||
|
@ -9,4 +9,4 @@
|
||||
# and systemd-coredump(8) and core(5) for the explanation of the
|
||||
# setting below.
|
||||
|
||||
kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %e
|
||||
kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %e
|
||||
|
@ -16,3 +16,6 @@ u systemd-resolve - "systemd Resolver"
|
||||
m4_ifdef(`ENABLE_TIMESYNCD',
|
||||
u systemd-timesync - "systemd Time Synchronization"
|
||||
)m4_dnl
|
||||
m4_ifdef(`ENABLE_COREDUMP',
|
||||
u systemd-coredump - "systemd Core Dumper"
|
||||
)m4_dnl
|
||||
|
1
units/.gitignore
vendored
1
units/.gitignore
vendored
@ -25,6 +25,7 @@
|
||||
/systemd-binfmt.service
|
||||
/systemd-bootchart.service
|
||||
/systemd-bus-proxyd.service
|
||||
/systemd-coredump@.service
|
||||
/systemd-firstboot.service
|
||||
/systemd-fsck-root.service
|
||||
/systemd-fsck@.service
|
||||
|
17
units/systemd-coredump.socket
Normal file
17
units/systemd-coredump.socket
Normal file
@ -0,0 +1,17 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# 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.
|
||||
|
||||
[Unit]
|
||||
Description=Process Core Dump Socket
|
||||
Documentation=man:systemd-coredump(8)
|
||||
DefaultDependencies=no
|
||||
|
||||
[Socket]
|
||||
ListenSequentialPacket=/run/systemd/coredump
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
MaxConnections=16
|
24
units/systemd-coredump@.service.in
Normal file
24
units/systemd-coredump@.service.in
Normal file
@ -0,0 +1,24 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# 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.
|
||||
|
||||
[Unit]
|
||||
Description=Process Core Dump
|
||||
Documentation=man:systemd-coredump(8)
|
||||
DefaultDependencies=no
|
||||
RequiresMountsFor=/var/lib/systemd/coredump
|
||||
Conflicts=shutdown.target
|
||||
After=systemd-remount-fs.service systemd-journald.socket
|
||||
Requires=systemd-journald.socket
|
||||
Before=shutdown.target
|
||||
|
||||
[Service]
|
||||
ExecStart=-@rootlibexecdir@/systemd-coredump
|
||||
Nice=9
|
||||
OOMScoreAdjust=500
|
||||
PrivateNetwork=yes
|
||||
ProtectSystem=full
|
||||
RuntimeMaxSec=5min
|
Loading…
x
Reference in New Issue
Block a user