aboutsummaryrefslogtreecommitdiff
path: root/examples/shutdown-1.0
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-20 15:12:52 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-20 15:12:52 +0200
commitc21dfaf836cf0eb5317035bc20395c751a205934 (patch)
tree1b9b812eb0153da450a7f9f14fd444dc0bc4b567 /examples/shutdown-1.0
parente09c426456cfd030cc868d93bbcb2e0a6933cabb (diff)
downloadbusybox-w32-c21dfaf836cf0eb5317035bc20395c751a205934.tar.gz
busybox-w32-c21dfaf836cf0eb5317035bc20395c751a205934.tar.bz2
busybox-w32-c21dfaf836cf0eb5317035bc20395c751a205934.zip
examples/shutdown-1.0: an example of reboot which does not signal init
For one, my inits know nothing about the concept of "shutting down the system". Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'examples/shutdown-1.0')
-rw-r--r--examples/shutdown-1.0/README30
-rwxr-xr-xexamples/shutdown-1.0/script/do_shutdown54
-rw-r--r--examples/shutdown-1.0/script/hardshutdown.c168
-rwxr-xr-xexamples/shutdown-1.0/script/hardshutdown.make.sh8
-rwxr-xr-xexamples/shutdown-1.0/script/shutdown64
-rwxr-xr-xexamples/shutdown-1.0/script/stop_storage81
-rwxr-xr-xexamples/shutdown-1.0/script/stop_tasks70
7 files changed, 475 insertions, 0 deletions
diff --git a/examples/shutdown-1.0/README b/examples/shutdown-1.0/README
new file mode 100644
index 000000000..40fe0ebed
--- /dev/null
+++ b/examples/shutdown-1.0/README
@@ -0,0 +1,30 @@
1# Replaces traditional overdesigned shutdown mechanism.
2#
3# No communication with init is necessary:
4# just ask all processes to exit.
5# Then unmount everything. Then reboot or power off.
6
7# Install /sbin/ symlinks named halt, reboot, poweroff
8# (and also possibly shutdown) to e.g.
9# /app/shutdown-1.0/script/shutdown:
10#
11ln -s /app/shutdown-1.0/script/shutdown /sbin/halt
12ln -s /app/shutdown-1.0/script/shutdown /sbin/reboot
13ln -s /app/shutdown-1.0/script/shutdown /sbin/poweroff
14#
15# shutdown spawns do_shutdown in new session, redirected to /dev/null,
16# tells user that shutdown is in progress, and sleeps
17# (for cosmetic reasons: do not confuse user by letting him
18# type more commands in this terminal).
19#
20# do_shutdown tries to switch to a VT console.
21# Then, (only if -r) it spawns a hardshutdown child, to reboot
22# unconditionally in 30 seconds if something later goes seriously bad.
23# Then it runs stop_tasks, writing to /var/log/reboot/YYYYMMDDhhmmss.log,
24# then it runs stop_storage.
25# Then it commands kernel to halt/reboot/poweroff, if requested.
26# Then it sleeps forever.
27#
28# Build the hardshutdown binary:
29#
30cd script && ./hardshutdown.make.sh
diff --git a/examples/shutdown-1.0/script/do_shutdown b/examples/shutdown-1.0/script/do_shutdown
new file mode 100755
index 000000000..0c1e0dce8
--- /dev/null
+++ b/examples/shutdown-1.0/script/do_shutdown
@@ -0,0 +1,54 @@
1#!/bin/sh
2# We are called with stdin/out/err = /dev/null
3
4resetgracetime=60
5
6logfile="/var/log/reboot/`date '+%Y%m%d%H%M%S'`.log"
7mkdir -p /var/log/reboot
8
9PATH=/sbin:/bin
10
11say() {
12 printf "\r%s\n\r" "$*"
13}
14
15# Since there is a potential for various fuckups during umount,
16# we start delayed hard reboot here which will forcibly
17# reboot hung box in a remote datacenter a thousand miles away ;)
18if test "$1" = "-r"; then
19 ./hardshutdown -r "$resetgracetime" &
20fi
21
22# Now, (try to) switch away from X and open a console. I've seen reboots
23# hung on open("/dev/console"), therefore we do it _after_ hardshutdown
24exec >/dev/console 2>&1
25
26if test "$1" = "-r"; then
27 say "* `date '+%H:%M:%S'` Scheduled hard reboot in $resetgracetime seconds"
28fi
29
30say "* `date '+%H:%M:%S'` Stopping tasks (see /var/log/reboot/* files)"
31# log reboot event to file. %Y%m%d%H%M%S: YYYYMMDDHHMMSS
32./stop_tasks >"$logfile" 2>&1
33
34# Dying X tends to leave us at semi-random vt. Try to fix that,
35# but if it doesn't work, proceed anyway.
36exec >/dev/null 2>&1
37chvt 1 & sleep 1
38exec >/dev/console 2>&1
39
40command -v ctrlaltdel >/dev/null && {
41 say "* `date '+%H:%M:%S'` Setting Ctrl-Alt-Del to 'hard'"
42 ctrlaltdel hard
43}
44
45say "* `date '+%H:%M:%S'` Stopping storage devices"
46# we can't log this: we are about to unmount everything!
47./stop_storage "$@"
48
49# If we have cmdline params, start hardshutdown with them
50test "$*" && ./hardshutdown "$@"
51
52# Just sleep endlessly...
53say "* `date '+%H:%M:%S'` You may now power off or press Ctrl-Alt-Del to reboot"
54while true; do sleep 32000; done
diff --git a/examples/shutdown-1.0/script/hardshutdown.c b/examples/shutdown-1.0/script/hardshutdown.c
new file mode 100644
index 000000000..c21ddad58
--- /dev/null
+++ b/examples/shutdown-1.0/script/hardshutdown.c
@@ -0,0 +1,168 @@
1/* Including <unistd.h> makes sure that on a glibc system
2 * <features.h> is included, which again defines __GLIBC__
3 */
4
5#include <unistd.h>
6#include <stdio.h> /* puts */
7#include <time.h> /* nanosleep */
8#include <errno.h>
9#include <stdlib.h>
10#include <string.h>
11
12
13/*
14 * Magic values required to use _reboot() system call.
15 */
16#define LINUX_REBOOT_MAGIC1 0xfee1dead
17#define LINUX_REBOOT_MAGIC2 672274793
18#define LINUX_REBOOT_MAGIC2A 85072278
19#define LINUX_REBOOT_MAGIC2B 369367448
20/*
21 * Commands accepted by the _reboot() system call.
22 *
23 * RESTART Restart system using default command and mode.
24 * HALT Stop OS and give system control to ROM monitor, if any.
25 * CAD_ON Ctrl-Alt-Del sequence causes RESTART command.
26 * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task.
27 * POWER_OFF Stop OS and remove all power from system, if possible.
28 * RESTART2 Restart system using given command string.
29 */
30#define LINUX_REBOOT_CMD_RESTART 0x01234567
31#define LINUX_REBOOT_CMD_HALT 0xCDEF0123
32#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF
33#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
34#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
35#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
36
37
38#define USE_LIBC
39
40#ifdef USE_LIBC
41
42/* libc version */
43#if defined __GLIBC__ && __GLIBC__ >= 2
44# include <sys/reboot.h>
45# define REBOOT(cmd) reboot(cmd)
46#else
47extern int reboot(int, int, int);
48# define REBOOT(cmd) reboot(LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,(cmd))
49#endif
50
51static int my_reboot(int cmd)
52{
53 return REBOOT(cmd);
54}
55
56#else /* no USE_LIBC */
57
58/* direct syscall version */
59#include <linux/unistd.h>
60
61#ifdef _syscall3
62_syscall3(int, reboot, int, magic, int, magic_too, int, cmd);
63#else
64/* Let us hope we have a 3-argument reboot here */
65extern int reboot(int, int, int);
66#endif
67
68static int my_reboot(int cmd)
69{
70 return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd);
71}
72
73#endif
74
75
76static void do_reboot(void)
77{
78 my_reboot(LINUX_REBOOT_CMD_RESTART);
79}
80static void do_poweroff(void)
81{
82 my_reboot(LINUX_REBOOT_CMD_POWER_OFF);
83}
84static void do_halt(void)
85{
86 my_reboot(LINUX_REBOOT_CMD_HALT);
87}
88
89static void usage(void)
90{
91 puts(
92 "Usage: hardshutdown -h|-r|-p [NN]\n"
93 " NN - seconds to sleep before requested action"
94 );
95 exit(1);
96}
97
98enum action_t {
99 SHUTDOWN, // do nothing
100 HALT,
101 POWEROFF,
102 REBOOT
103};
104
105int main(int argc, char *argv[])
106{
107 struct timespec t = {0,0};
108 enum action_t action = SHUTDOWN;
109 int c, i;
110 char *prog, *ptr;
111
112 //if (*argv[0] == '-') argv[0]++; /* allow shutdown as login shell */
113 prog = argv[0];
114 ptr = strrchr(prog,'/');
115 if (ptr)
116 prog = ptr+1;
117
118 for (c=1; c < argc; c++) {
119 if (argv[c][0] >= '0' && argv[c][0] <= '9') {
120 t.tv_sec = strtol(argv[c], NULL, 10);
121 continue;
122 }
123 if (argv[c][0] != '-') {
124 usage();
125 return 1;
126 }
127 for (i=1; argv[c][i]; i++) {
128 switch (argv[c][i]) {
129 case 'h':
130 action = HALT;
131 break;
132 case 'p':
133 action = POWEROFF;
134 break;
135 case 'r':
136 action = REBOOT;
137 break;
138 default:
139 usage();
140 return 1;
141 }
142 }
143 }
144
145 if (action==SHUTDOWN) {
146 usage();
147 return 1;
148 }
149
150 chdir("/");
151 while (nanosleep(&t,&t)<0)
152 if (errno!=EINTR) break;
153
154 switch (action) {
155 case HALT:
156 do_halt();
157 break;
158 case POWEROFF:
159 do_poweroff();
160 break;
161 case REBOOT:
162 do_reboot();
163 break;
164 default: /* SHUTDOWN */
165 break;
166 }
167 return 1;
168}
diff --git a/examples/shutdown-1.0/script/hardshutdown.make.sh b/examples/shutdown-1.0/script/hardshutdown.make.sh
new file mode 100755
index 000000000..90f8c5456
--- /dev/null
+++ b/examples/shutdown-1.0/script/hardshutdown.make.sh
@@ -0,0 +1,8 @@
1#!/bin/sh
2
3gcc -Wall -Os -o hardshutdown hardshutdown.c
4strip hardshutdown
5
6#or:
7#diet gcc -Wall -o hardshutdown hardshutdown.c
8#elftrunc hardshutdown
diff --git a/examples/shutdown-1.0/script/shutdown b/examples/shutdown-1.0/script/shutdown
new file mode 100755
index 000000000..dbab9d81e
--- /dev/null
+++ b/examples/shutdown-1.0/script/shutdown
@@ -0,0 +1,64 @@
1#!/bin/sh
2
3PATH=/sbin:/usr/sbin:/bin:/usr/bin
4
5# Usually, /sbin/ has symlinks named halt, reboot, poweroff
6# (and also possibly shutdown) to e.g.
7# /app/shutdown-1.0/script/shutdown (this file).
8cd /app/shutdown-1.0/script || exit 1
9test -x ./do_shutdown || exit 1
10test -x ./hardshutdown || exit 1
11
12# "reboot -f" -> "shutdown -f -r" -> "hardshutdown -r" -> immediate reboot
13# "reboot" -> "shutdown -r" -> "do_shutdown -r"
14# ^^^^^^^^^^^^^^^^^^ similarly for halt, poweroff.
15# "shutdown" -> "do_shutdown" (everything killed/unmounted, but kernel not asked to do any poweroff etc)
16force=""
17test x"$1" = x"-f" && {
18 force="-f"
19 shift
20}
21test ! "$*" && test x"${0##*/}" = x"halt" && exec "$0" $force -h
22test ! "$*" && test x"${0##*/}" = x"reboot" && exec "$0" $force -r
23test ! "$*" && test x"${0##*/}" = x"poweroff" && exec "$0" $force -p
24# We have something else than allowed parameters?
25test x"$*" = x"" || test x"$*" = x"-h" || test x"$*" = x"-r" || test x"$*" = x"-p" || {
26 echo "Syntax: $0 [-f] [-h/-r/-p]"
27 exit 1
28}
29
30# Emergency shutdown?
31test "$force" && {
32 exec ./hardshutdown "$@"
33 exit 1
34}
35
36# Normal shutdown
37
38# We must have these executables on root fs
39# (mount/umount aren't checked, all systems are ok versus that):
40test -x /bin/killall5 -o -x /sbin/killall5 || exit 1
41test -x /bin/ps -o -x /sbin/ps || exit 1
42test -x /bin/date -o -x /sbin/date || exit 1
43test -x /bin/xargs -o -x /sbin/xargs || exit 1
44test -x /bin/wc -o -x /sbin/wc || exit 1
45test -x /bin/cat -o -x /sbin/cat || exit 1
46test -x /bin/sort -o -x /sbin/sort || exit 1
47
48i="`ulimit -n`"
49echo -n "Closing file descriptors $i-3... "
50while test "$i" -ge 3; do
51 eval "exec $i>&-"
52 i=$((i-1))
53done
54
55echo "Shutting down. Please stand by..."
56
57# setsid & /dev/null:
58# make it a process leader & detach it from current tty.
59# Why /dev/null and not /dev/console?
60# I have seen a system which locked up while opening /dev/console
61# due to the bug (?) in keyboard driver.
62setsid env - PATH="$PATH" ./do_shutdown "$@" </dev/null >/dev/null 2>&1 &
63
64while true; do read junk; done
diff --git a/examples/shutdown-1.0/script/stop_storage b/examples/shutdown-1.0/script/stop_storage
new file mode 100755
index 000000000..1be5f735b
--- /dev/null
+++ b/examples/shutdown-1.0/script/stop_storage
@@ -0,0 +1,81 @@
1#!/bin/sh
2# Do unmount/remount-ro. Wait.
3# KILL everybody. Wait.
4# Repeat.
5
6umountcnt=2
7writeout=0 # increase if your kernel doesn ot guarantee writes to complete
8
9# No /usr - we are expecting all binaries to be accessible
10# from root fs alone
11PATH=/sbin:/bin
12
13say() {
14 printf "\r%s\n\r" "$*"
15}
16
17showps() {
18 # sleep 1 ensures that xargs will have time to start up
19 # this makes pslist less prone to random jitter
20 pslist=`{ sleep 1; ps -A -o comm=; } | sort | xargs`
21 pscnt=$(( `say "$pslist" | wc -w` + 0 ))
22 if test x"$VERBOSE" = x; then
23 say "* `date '+%H:%M:%S'` $pscnt processes"
24 else
25 say "* `date '+%H:%M:%S'` Processes ($pscnt): $pslist"
26 fi
27}
28
29say "<*> `date '+%Y-%m-%d %H:%M:%S'` Executing '$0 $*'"
30
31showps
32
33i="$umountcnt"
34while test "$i" -gt 0; do
35 say "* `date '+%H:%M:%S'` Unmounting filesystems"
36 umount -a -n -r -f
37 # In case we unmounted proc...
38 test -e /proc/version || mount -t proc none /proc
39 # Remounting / RO isn't necessary when /etc/mtab is linked to /proc/mounts:
40 # already done. But let's be more paranoid here...
41 say "* `date '+%H:%M:%S'` Remounting root filesystem read-only"
42 mount -n -o remount,ro /
43 say "* `date '+%H:%M:%S'` Freeing loop devices"
44 for a in /dev/loop*; do
45 test -b "$a" && losetup -d "$a"
46 done
47 say "* `date '+%H:%M:%S'` Syncing"
48 sync
49 say "* `date '+%H:%M:%S'` Executing: killall5 -KILL"
50 killall5 -9
51 showps
52 i=$((i-1))
53done
54
55say "* `date '+%H:%M:%S'` Filesystem status (/proc/mounts)"
56cat /proc/mounts \
57| {
58 bad=false
59 while read dev mntpoint fstype opt n1 n2; do
60 case "$fstype" in
61 ( proc | sysfs | usbfs | devpts | rpc_pipefs | binfmt_misc | autofs | rootfs | tmpfs | ramfs )
62 say "$dev $mntpoint $fstype $opt $n1 $n2"
63 continue
64 ;;
65 esac
66 if test "${opt:0:2}" = "rw"; then
67 say "$dev $mntpoint $fstype $opt $n1 $n2 - RW!"
68 bad=true
69 else
70 say "$dev $mntpoint $fstype $opt $n1 $n2"
71 fi
72 done
73 if $bad; then
74 say "ERROR: we have filesystems mounted RW! Press <Enter> (^J)..."
75 read junk </dev/console
76 #sh </dev/console >&0 2>&0 # debug
77 fi
78}
79
80# Disk cache writeout
81sleep "$writeout"
diff --git a/examples/shutdown-1.0/script/stop_tasks b/examples/shutdown-1.0/script/stop_tasks
new file mode 100755
index 000000000..2d752a3da
--- /dev/null
+++ b/examples/shutdown-1.0/script/stop_tasks
@@ -0,0 +1,70 @@
1#!/bin/sh
2# We are trying to be nice.
3# TERM everybody. Give them some time to die.
4# KILL might make some filesystems non-unmountable,
5# so we'll do it in stop_storage instead.
6
7killcnt=30
8
9PATH=/sbin:/usr/sbin:/bin:/usr/bin
10
11echo "<*> `date '+%Y-%m-%d %H:%M:%S'` Executing '$0 $*'"
12
13showps() {
14 # sleep 1 ensures that xargs will have time to start up.
15 # This makes pslist less prone to random jitter.
16 pslist=`{ sleep 1; ps -A -o comm=; } | sort | xargs`
17 pscnt=$(( `echo "$pslist" | wc -w` + 0 ))
18 if test x"$VERBOSE" = x; then
19 echo "* `date '+%H:%M:%S'` $pscnt processes"
20 else
21 echo "* `date '+%H:%M:%S'` Processes ($pscnt): $pslist"
22 fi
23}
24
25# Sync.
26# Rationale: sometimes buggy root processes can
27# hang the system when killed (X for example may have problems
28# with restoring text mode on a poorly supported hardware).
29# These are bugs and must be fixed, but until then users will lose
30# dirty data on shutdown! Let's make that less likely.
31sync &
32
33# Send SIGTERMs. If list of processes changes, proceed slower.
34# If it has stabilised (all who wanted to, exited), proceed faster.
35showps
36i="$killcnt"
37while test "$i" -gt 0; do
38 echo "* `date '+%H:%M:%S'` Sending CONT, TERM" #, HUP"
39 # I've seen "killall5 2.86" which doesn't grok signal names!
40 killall5 -18
41 killall5 -15
42 #killall5 -1 # HUP: because interactive bash does not die on TERM...
43 # but init will reread /etc/inittab on HUP and my /etc is on non root fs!
44 # -> umounts will complain.
45 oldpslist="$pslist"
46 showps
47 if test x"$pslist" = x"$oldpslist"; then
48 i=$((i-8))
49 fi
50 i=$((i-2))
51done
52
53echo "* `date '+%H:%M:%S'` Turning off swap"
54swapoff -a
55cat /proc/swaps | grep -v ^Filename | cut -d ' ' -f1 \
56| while read -r line; do
57 test "$line" && {
58 echo swapoff "$line"
59 swapoff "$line"
60 }
61done
62
63echo "* /proc/swaps:"
64cat /proc/swaps
65echo "* /proc/mounts:"
66cat /proc/mounts
67echo "* ps -A e:"
68ps -A e
69echo "* top -bn1:"
70top -bn1