diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-12-22 22:14:05 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-12-22 22:19:03 +0100 |
commit | 09812eb764b440651f3ff4cb5d37bd343f800560 (patch) | |
tree | 75a7a86e915c814ded076cd0efc84d20018ff13b | |
parent | 565a9388f261c6e459e1726e358284ff687ec941 (diff) |
sd-daemon: introduce sd_watchdog_enabled() for parsing $WATCHDOG_USEC
Also, introduce a new environment variable named $WATCHDOG_PID which
cotnains the PID of the process that is supposed to send the keep-alive
events. This is similar how $LISTEN_FDS and $LISTEN_PID work together,
and protects against confusing processes further down the process tree
due to inherited environment.
-rw-r--r-- | Makefile-man.am | 2 | ||||
-rw-r--r-- | man/sd-daemon.xml | 1 | ||||
-rw-r--r-- | man/sd_notify.xml | 17 | ||||
-rw-r--r-- | man/sd_watchdog_enabled.xml | 198 | ||||
-rw-r--r-- | src/core/execute.c | 18 | ||||
-rw-r--r-- | src/core/execute.h | 1 | ||||
-rw-r--r-- | src/core/mount.c | 1 | ||||
-rw-r--r-- | src/core/service.c | 9 | ||||
-rw-r--r-- | src/core/socket.c | 1 | ||||
-rw-r--r-- | src/core/swap.c | 1 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-event.c | 11 | ||||
-rw-r--r-- | src/libsystemd-daemon/libsystemd-daemon.sym | 5 | ||||
-rw-r--r-- | src/libsystemd-daemon/sd-daemon.c | 66 | ||||
-rw-r--r-- | src/systemd/sd-daemon.h | 21 |
14 files changed, 326 insertions, 26 deletions
diff --git a/Makefile-man.am b/Makefile-man.am index 968de7da62..df8860a3f0 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -41,6 +41,7 @@ MANPAGES += \ man/sd_journal_stream_fd.3 \ man/sd_listen_fds.3 \ man/sd_notify.3 \ + man/sd_watchdog_enabled.3 \ man/shutdown.8 \ man/sysctl.d.5 \ man/systemctl.1 \ @@ -1133,6 +1134,7 @@ EXTRA_DIST += \ man/sd_seat_get_active.xml \ man/sd_session_is_active.xml \ man/sd_uid_get_state.xml \ + man/sd_watchdog_enabled.xml \ man/shutdown.xml \ man/sysctl.d.xml \ man/systemctl.xml \ diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml index 6e804e1a6c..74011123bb 100644 --- a/man/sd-daemon.xml +++ b/man/sd-daemon.xml @@ -167,6 +167,7 @@ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_is_fifo</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>, diff --git a/man/sd_notify.xml b/man/sd_notify.xml index 55965ffce4..683967cd48 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -164,11 +164,15 @@ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. It is recommended to send this message if the - <varname>WATCHDOG_USEC=</varname> - environment variable has been set for - the service process, in every half the - time interval that is specified in the - variable.</para></listitem> + <varname>$WATCHDOG_PID</varname> + environment variable has been set to + the PID of the service process, in + every half the time interval that is + specified in the + <varname>$WATCHDOG_USEC</varname> + environment variable. See + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + for details.</para></listitem> </varlistentry> </variablelist> @@ -311,7 +315,8 @@ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_watchdog_enabled.xml b/man/sd_watchdog_enabled.xml new file mode 100644 index 0000000000..e42ae430ec --- /dev/null +++ b/man/sd_watchdog_enabled.xml @@ -0,0 +1,198 @@ +<?xml version='1.0'?> <!--*-nxml-*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + 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/>. +--> + +<refentry id="sd_watchdog_enabled"> + + <refentryinfo> + <title>sd_watchdog_enabled</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_watchdog_enabled</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_watchdog_enabled</refname> + <refpurpose>Check whether the service manager expects watchdog keep-alive notifications from a service</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-daemon.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_watchdog_enabled</function></funcdef> + <paramdef>int <parameter>unset_environment</parameter></paramdef> + <paramdef>const uint64_t *<parameter>usec</parameter></paramdef> + </funcprototype> + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + <para><function>sd_watchdog_enabled()</function> may + be called by a service to detect whether the service + manager expects regular keep-alive watchdog + notification events from it, and the timeout after + which the manager will act on the service if it did + not get such a notification.</para> + + <para>If the <parameter>unset_environment</parameter> + parameter is non-zero, + <function>sd_watchdog_enabled()</function> will unset + the <varname>$WATCHDOG_USEC</varname> and + <varname>$WATCHDOG_PID</varname> environment variables + before returning (regardless whether the function call + itself succeeded or not). Further calls to + <function>sd_watchdog_enabled()</function> will then + return with zero, but the variable is no longer + inherited by child processes.</para> + + <para>If the <parameter>usec</parameter> parameter is + non-NULL <function>sd_watchdog_enabled()</function> + will return the timeout in µs for the watchdog + logic. The service manager will usually terminate a + service when it did not get a notification message + within the specified time after startup and after each + previous message. It is recommended that a daemon + sends a keep-alive notification message to the service + manager every half of the time returned + here. Notification messages may be sent with + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> + with a message string of + <literal>WATCHDOG=1</literal>.</para> + + <para>To enable service supervision with the watchdog + logic use <varname>WatchdogSec=</varname> in service + files. See + <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On failure, this call returns a negative + errno-style error code. If the service manager expects + watchdog keep-alive notification messages to be sent, + > 0 is returned, otherwise 0 is returned. Only if + the return value is > 0 the + <parameter>usec</parameter> parameter is valid after + the call.</para> + </refsect1> + + <refsect1> + <title>Notes</title> + + <para>This function is provided by the reference + implementation of APIs for new-style daemons and + distributed with the systemd package. The algorithm + it implements is simple, and can easily be + reimplemented in daemons if it is important to support + this interface without using the reference + implementation.</para> + + <para>Internally, this functions parses the + <varname>$WATCHDOG_PID</varname> and + <varname>$WATCHDOG_USEC</varname> environment + variable. The call will ignore these variables if + <varname>$WATCHDOG_PID</varname> does containe the PID + of the current process, under the assumption that in + that case the variables were set for a different + process further up the process tree.</para> + + <para>For details about the algorithm check the + liberally licensed reference implementation sources: + <ulink url="http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/sd-daemon.c"/> + and <ulink + url="http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h"/></para> + + <para><function>sd_watchdog_enabled()</function> is + implemented in the reference implementation's + <filename>sd-daemon.c</filename> and + <filename>sd-daemon.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <constant>libsystemd-daemon</constant> <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming these APIs + may copy the implementation into their source + tree. For more details about the reference + implementation see + <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>If the reference implementation is used as + drop-in files and -DDISABLE_SYSTEMD is set during + compilation, these functions will always return 0 and + otherwise become a NOP.</para> + </refsect1> + + <refsect1> + <title>Environment</title> + + <variablelist class='environment-variables'> + <varlistentry> + <term><varname>$WATCHDOG_PID</varname></term> + + <listitem><para>Set by the system + manager for supervised process for + which watchdog support is enabled, and + contains the PID of that process. See + above for details.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>$WATCHDOG_USEC</varname></term> + + <listitem><para>Set by the system + manager for supervised process for + which watchdog support is enabled, and + contains the watchdog timeout in µs + See above for + details.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/src/core/execute.c b/src/core/execute.c index 4265717895..9b33ec0ec5 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1020,6 +1020,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { static int build_environment( ExecContext *c, unsigned n_fds, + usec_t watchdog_usec, const char *home, const char *username, const char *shell, @@ -1032,7 +1033,7 @@ static int build_environment( assert(c); assert(ret); - our_env = new(char*, 8); + our_env = new0(char*, 10); if (!our_env) return -ENOMEM; @@ -1046,6 +1047,16 @@ static int build_environment( our_env[n_env++] = x; } + if (watchdog_usec > 0) { + if (asprintf(&x, "WATCHDOG_PID=%lu", (unsigned long) getpid()) < 0) + return -ENOMEM; + our_env[n_env++] = x; + + if (asprintf(&x, "WATCHDOG_USEC=%llu", (unsigned long long) watchdog_usec) < 0) + return -ENOMEM; + our_env[n_env++] = x; + } + if (home) { x = strappend("HOME=", home); if (!x) @@ -1084,7 +1095,7 @@ static int build_environment( } our_env[n_env++] = NULL; - assert(n_env <= 8); + assert(n_env <= 10); *ret = our_env; our_env = NULL; @@ -1104,6 +1115,7 @@ int exec_spawn(ExecCommand *command, CGroupControllerMask cgroup_supported, const char *cgroup_path, const char *unit_id, + usec_t watchdog_usec, int idle_pipe[4], ExecRuntime *runtime, pid_t *ret) { @@ -1560,7 +1572,7 @@ int exec_spawn(ExecCommand *command, } } - err = build_environment(context, n_fds, home, username, shell, &our_env); + err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env); if (r < 0) { r = EXIT_MEMORY; goto fail_child; diff --git a/src/core/execute.h b/src/core/execute.h index bd3db0b633..989373f481 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -181,6 +181,7 @@ int exec_spawn(ExecCommand *command, CGroupControllerMask cgroup_mask, const char *cgroup_path, const char *unit_id, + usec_t watchdog_usec, int pipe_fd[2], ExecRuntime *runtime, pid_t *ret); diff --git a/src/core/mount.c b/src/core/mount.c index 2b7934e404..09efa1b6e0 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -787,6 +787,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { UNIT(m)->manager->cgroup_supported, UNIT(m)->cgroup_path, UNIT(m)->id, + 0, NULL, m->exec_runtime, &pid); diff --git a/src/core/service.c b/src/core/service.c index 87eaa29378..4eb3d9e668 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1750,7 +1750,7 @@ static int service_spawn( if (r < 0) goto fail; - our_env = new0(char*, 5); + our_env = new0(char*, 4); if (!our_env) { r = -ENOMEM; goto fail; @@ -1768,12 +1768,6 @@ static int service_spawn( goto fail; } - if (s->watchdog_usec > 0) - if (asprintf(our_env + n_env++, "WATCHDOG_USEC=%llu", (unsigned long long) s->watchdog_usec) < 0) { - r = -ENOMEM; - goto fail; - } - if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM) if (asprintf(our_env + n_env++, "MANAGERPID=%lu", (unsigned long) getpid()) < 0) { r = -ENOMEM; @@ -1804,6 +1798,7 @@ static int service_spawn( UNIT(s)->manager->cgroup_supported, path, UNIT(s)->id, + s->watchdog_usec, s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL, s->exec_runtime, &pid); diff --git a/src/core/socket.c b/src/core/socket.c index 2442221355..31fc2a2526 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1254,6 +1254,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { UNIT(s)->manager->cgroup_supported, UNIT(s)->cgroup_path, UNIT(s)->id, + 0, NULL, s->exec_runtime, &pid); diff --git a/src/core/swap.c b/src/core/swap.c index 79862e5b87..e0627db965 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -645,6 +645,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { UNIT(s)->manager->cgroup_supported, UNIT(s)->cgroup_path, UNIT(s)->id, + 0, NULL, s->exec_runtime, &pid); diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c index a1baac52aa..bfc798ca6e 100644 --- a/src/libsystemd-bus/sd-event.c +++ b/src/libsystemd-bus/sd-event.c @@ -2164,17 +2164,10 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { if (b) { struct epoll_event ev = {}; - const char *env; - env = getenv("WATCHDOG_USEC"); - if (!env) - return false; - - r = safe_atou64(env, &e->watchdog_period); - if (r < 0) + r = sd_watchdog_enabled(false, &e->watchdog_period); + if (r <= 0) return r; - if (e->watchdog_period <= 0) - return -EIO; /* Issue first ping immediately */ sd_notify(false, "WATCHDOG=1"); diff --git a/src/libsystemd-daemon/libsystemd-daemon.sym b/src/libsystemd-daemon/libsystemd-daemon.sym index f440238931..aa9be51c6a 100644 --- a/src/libsystemd-daemon/libsystemd-daemon.sym +++ b/src/libsystemd-daemon/libsystemd-daemon.sym @@ -25,3 +25,8 @@ global: local: *; }; + +LIBSYSTEMD_DAEMON_209 { +global: + sd_watchdog_enabled; +} LIBSYSTEMD_DAEMON_31; diff --git a/src/libsystemd-daemon/sd-daemon.c b/src/libsystemd-daemon/sd-daemon.c index 485b301023..94230c9ed6 100644 --- a/src/libsystemd-daemon/sd-daemon.c +++ b/src/libsystemd-daemon/sd-daemon.c @@ -518,3 +518,69 @@ _sd_export_ int sd_booted(void) { return !!S_ISDIR(st.st_mode); #endif } + +_sd_export_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { + +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + unsigned long long ll; + unsigned long l; + const char *e; + char *p = NULL; + int r; + + e = getenv("WATCHDOG_PID"); + if (!e) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + if (errno > 0) { + r = -errno; + goto finish; + } + if (!p || p == e || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + /* Is this for us? */ + if (getpid() != (pid_t) l) { + r = 0; + goto finish; + } + + e = getenv("WATCHDOG_USEC"); + if (!e) { + r = -EINVAL; + goto finish; + } + + errno = 0; + ll = strtoull(e, &p, 10); + if (errno > 0) { + r = -errno; + goto finish; + } + if (!p || p == e || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + if (usec) + *usec = ll; + + r = 1; + +finish: + if (unset_environment) { + unsetenv("WATCHDOG_PID"); + unsetenv("WATCHDOG_USEC"); + } + + return r; +#endif +} diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index daa3f4c857..43deb8cc7d 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -186,6 +186,8 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t the file descriptor is a POSIX Message Queue of the specified name, 0 otherwise. If path is NULL a message queue name check is not done. Returns a negative errno style error code on failure. + + See sd_is_mq(3) for more information. */ int sd_is_mq(int fd, const char *path); @@ -220,7 +222,8 @@ int sd_is_mq(int fd, const char *path); WATCHDOG=1 Tells systemd to update the watchdog timestamp. Services using this feature should do this in regular intervals. A watchdog framework can use the - timestamps to detect failed services. + timestamps to detect failed services. Also see + sd_watchdog_enabled() below. Daemons can choose to send additional variables. However, it is recommended to prefix variable names not listed above with X_. @@ -275,6 +278,22 @@ int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_( */ int sd_booted(void); +/* + Returns > 0 if the service manager expects watchdog keep-alive + events to be sent regularly via sd_notify(0, "WATCHDOG=1"). Returns + 0 if it does not expect this. If the usec argument is non-NULL + returns the watchdog timeout in µs after which the service manager + will act on a process that has not sent a watchdog keep alive + message. This function is useful to implement services that + recognize automatically if they are being run under supervision of + systemd with WatchdogSec= set. It is recommended for clients to + generate keep-alive pings via sd_notify(0, "WATCHDOG=1") every half + of the returned time. + + See sd_watchdog_enabled(3) for more information. +*/ +int sd_watchdog_enabled(int unset_environment, uint64_t *usec); + #ifdef __cplusplus } #endif |