[systemd-devel] [PATCH 3/4] Adding halt binary to shutdown the system
fidencio at profusion.mobi
fidencio at profusion.mobi
Tue Oct 5 08:41:08 PDT 2010
From: Fabiano Fidencio <fidencio at profusion.mobi>
This functions are working as follows:
- Send a SIGTERM to all processes that may be finished.
- Send a SIGKILL to all processes that still live and
may be finished.
- Try to mount all mount points
- Try to remount read-only all mount points that can't
be umounted
- Umount all swap devices.
- Call [poweroff|halt|reboot|kexec]
TODO:
- umount dms
- umount loopbacks
---
Makefile.am | 15 +++++
src/shutdown.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 176 insertions(+), 0 deletions(-)
create mode 100644 src/shutdown.c
diff --git a/Makefile.am b/Makefile.am
index 0a33c06..2db3827 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,7 @@ tmpfilesdir=$(sysconfdir)/tmpfiles.d
# And these are the special ones for /
rootdir=@rootdir@
rootbindir=$(rootdir)/bin
+rootsbindir=$(rootdir)/sbin
rootlibexecdir=$(rootdir)/lib/systemd
systemunitdir=$(rootdir)/lib/systemd/system
@@ -50,9 +51,11 @@ AM_CPPFLAGS = \
-DSESSION_DATA_UNIT_PATH=\"$(sessionunitdir)\" \
-DCGROUP_AGENT_PATH=\"$(rootlibexecdir)/systemd-cgroups-agent\" \
-DSYSTEMD_BINARY_PATH=\"$(rootbindir)/systemd\" \
+ -DSYSTEMD_SHUTDOWN_BINARY_PATH=\"$(rootlibexecdir)/systemd-shutdown\" \
-DSYSTEMCTL_BINARY_PATH=\"$(rootbindir)/systemctl\" \
-DRUNTIME_DIR=\"$(localstatedir)/run\" \
-DRANDOM_SEED=\"$(localstatedir)/lib/random-seed\" \
+ -DKEXEC_BINARY_PATH=\"$(rootsbindir)/kexec\" \
-I $(top_srcdir)/src
if TARGET_GENTOO
@@ -89,6 +92,7 @@ rootlibexec_PROGRAMS = \
systemd-update-utmp \
systemd-random-seed \
systemd-shutdownd \
+ systemd-shutdown \
systemd-modules-load \
systemd-remount-api-vfs \
systemd-kmsg-syslogd \
@@ -628,6 +632,17 @@ systemd_shutdownd_CFLAGS = \
systemd_shutdownd_LDADD = \
libsystemd-basic.la
+systemd_shutdown_SOURCES = \
+ src/mount-setup.c \
+ src/umount.c \
+ src/shutdown.c
+
+systemd_shutdown_CFLAGS = \
+ $(AM_CFLAGS)
+
+systemd_shutdown_LDADD = \
+ libsystemd-basic.la
+
systemd_modules_load_SOURCES = \
src/modules-load.c
diff --git a/src/shutdown.c b/src/shutdown.c
new file mode 100644
index 0000000..95c19a3
--- /dev/null
+++ b/src/shutdown.c
@@ -0,0 +1,161 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 ProFUSION embedded systems
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "umount.h"
+#include "util.h"
+
+#define TIMEOUT_USEC 5000000
+
+static bool ignore_proc(pid_t pid) {
+ if (pid == 1)
+ return true;
+
+ return false;
+}
+
+static unsigned int killall(DIR *dir, int sign) {
+ struct dirent *d;
+ pid_t pid;
+ unsigned int processes = 0;
+
+ while ((d = readdir(dir))) {
+
+ if ((pid = atoi(d->d_name)) == 0)
+ continue;
+
+ if (ignore_proc(pid))
+ continue;
+
+ kill(pid, sign);
+ processes++;
+ }
+
+ return processes;
+}
+
+static unsigned int send_signal(DIR *dir, int sign) {
+ sigset_t mask;
+ usec_t until;
+ unsigned int processes;
+ struct timespec ts;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+
+ processes = killall(dir, sign);
+
+ until = now(CLOCK_REALTIME) + TIMEOUT_USEC;
+ for (;;) {
+ usec_t n;
+
+ for (;;) {
+ n = now(CLOCK_REALTIME);
+ if (n >= until)
+ goto finish;
+
+ if (waitpid(-1, NULL, WNOHANG) <= 0)
+ break;
+
+ if (--processes == 0)
+ goto finish;
+ }
+
+ timespec_store(&ts, until - n);
+ sigtimedwait(&mask, NULL, &ts);
+ }
+
+finish:
+ return processes;
+}
+
+int main(int argc, char *argv[]) {
+ DIR *dir;
+ int cmd;
+ const char *args[5] = {KEXEC_BINARY_PATH, "-e", "-x", "-f", NULL};
+
+ if (getpid() != 1)
+ return EXIT_FAILURE;
+
+ if (argc != 2)
+ return EXIT_FAILURE;
+
+ log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+ log_parse_environment();
+ log_open();
+
+ if (streq(argv[1], "reboot"))
+ cmd = RB_AUTOBOOT;
+ else if (streq(argv[1], "poweroff"))
+ cmd = RB_POWER_OFF;
+ else if (streq(argv[1], "halt"))
+ cmd = RB_HALT_SYSTEM;
+
+ /* lock us into memory */
+ mlockall(MCL_CURRENT|MCL_FUTURE);
+
+ /* opening /proc to read all processes */
+ if ((dir = opendir("/proc")) == NULL)
+ return EXIT_FAILURE;
+
+ /* sending SIGTERM and SIGKILL to all processes */
+ kill(-1, SIGSTOP);
+ log_info("Sending SIGTERM To Processes");
+ if ((send_signal(dir, SIGTERM)) > 0) {
+ log_info("Sending SIGKILL To Processes");
+ send_signal(dir, SIGKILL);
+ }
+ kill(-1, SIGCONT);
+
+ /* preventing that we won't block umounts */
+ if (chdir("/") == -1)
+ return EXIT_FAILURE;
+
+ /* umount all mountpoints, swaps, dm and loops */
+ log_info("Unmounting Filesystems");
+ umount_all();
+ log_info("Disabling Swaps");
+ swapoff_all();
+ /* FIXME:
+ * - undm_all()
+ * - unloop_all()
+ * - handling devicemapper
+ */
+
+ sync();
+
+ if (cmd == RB_AUTOBOOT)
+ execv(args[0], (char * const *) args);
+
+ return reboot(cmd);
+}
--
1.7.3
More information about the systemd-devel
mailing list