summaryrefslogtreecommitdiff
path: root/src/shutdown.c
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2017-02-27 09:26:59 -0800
committerMichael Forney <mforney@mforney.org>2017-02-27 09:28:37 -0800
commit2513d3050282a0870eb22c8d394c4b50dca9bd1b (patch)
treec2b0c3dde228fab6ad1b03039528a977c65457b1 /src/shutdown.c
parent858e99ecdbb611c149434bf0381a2155ec3f3bf4 (diff)
Move util -> src
Diffstat (limited to 'src/shutdown.c')
-rw-r--r--src/shutdown.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/shutdown.c b/src/shutdown.c
new file mode 100644
index 00000000..06ff3e55
--- /dev/null
+++ b/src/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;
+ }
+}