summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2016-12-10 01:09:50 -0800
committerMichael Forney <mforney@mforney.org>2016-12-10 12:05:02 -0800
commitf5b8ae3d94ccc876fd8aa75a8837cae7feccd9da (patch)
treeec2c91d781e77597bb2a974f2752101d004cbee8 /util
parent80fa7ed8020c775d80654c7704d3d2ffa020fbd1 (diff)
Add shutdown utility for rc.shutdown
Diffstat (limited to 'util')
-rw-r--r--util/gen.rc7
-rw-r--r--util/shutdown.c87
2 files changed, 93 insertions, 1 deletions
diff --git a/util/gen.rc b/util/gen.rc
index 4dcbd052..aa7c175c 100644
--- a/util/gen.rc
+++ b/util/gen.rc
@@ -1,5 +1,10 @@
set srcdir '$dir'
-cflags -Wall -Wextra '-std=c11' -pedantic
+cflags\
+ -Wall -Wextra -Wno-unused-parameter -pedantic\
+ '-std=c11'
exe perms-hook perms-hook.c
file libexec/oasis/perms-hook '$outdir'/perms-hook 755
+
+exe shutdown shutdown.c
+file libexec/oasis/shutdown '$outdir'/shutdown 755
diff --git a/util/shutdown.c b/util/shutdown.c
new file mode 100644
index 00000000..06ff3e55
--- /dev/null
+++ b/util/shutdown.c
@@ -0,0 +1,87 @@
+/* See LICENSE file for copyright and license details. */
+#define _XOPEN_SOURCE 700
+#include <errno.h>
+#include <mntent.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <unistd.h>
+
+static noreturn void
+usage()
+{
+ fprintf(stderr, "usage: shutdown [-hpr]\n");
+ exit(2);
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ char **dirs = NULL;
+ size_t n = 0;
+ struct mntent *mnt;
+ int cmd = RB_POWER_OFF;
+
+ while (*++argv && (*argv)[0] == '-' && (*argv)[1]) {
+ switch ((*argv)[1]) {
+ case 'h':
+ cmd = RB_HALT_SYSTEM;
+ break;
+ case 'p':
+ cmd = RB_POWER_OFF;
+ break;
+ case 'r':
+ cmd = RB_AUTOBOOT;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (*argv)
+ usage();
+
+ if (getsid(0) != getpid()) {
+ fprintf(stderr, "must be session leader\n");
+ return 1;
+ }
+
+ sync();
+ kill(-1, SIGTERM);
+ sleep(2);
+ kill(-1, SIGKILL);
+
+ sync();
+ fp = setmntent("/proc/mounts", "r");
+ if (!fp) {
+ perror("setmntent");
+ goto reboot;
+ }
+ while ((mnt = getmntent(fp))) {
+ if (!(dirs = realloc(dirs, ++n * sizeof(*dirs)))) {
+ perror("realloc");
+ break;
+ }
+ if (!(dirs[n - 1] = strdup(mnt->mnt_dir))) {
+ perror("strdup");
+ break;
+ }
+ }
+ endmntent(fp);
+ while (n) {
+ if (umount(dirs[--n]) < 0)
+ fprintf(stderr, "umount %s: %s\n", dirs[n], strerror(errno));
+ free(dirs[n]);
+ }
+ free(dirs);
+
+reboot:
+ if (reboot(cmd) < 0) {
+ perror("reboot");
+ return 1;
+ }
+}