Create a BusyBox based Emergency Shell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
########################################################################### | |
### Creates a BusyBox emergency shell in RAM | |
### | |
### Script by Jack Zielke <eshell@linuxcoffee.com> | |
### http://linuxcoffee.com/eshell | |
### | |
### BusyBox is maintained by Denys Vlasenko, and licensed under the GNU | |
### GENERAL PUBLIC LICENSE version 2. | |
### http://www.busybox.net/ | |
########################################################################### | |
### | |
### THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY OF ANY KIND. | |
### | |
########################################################################### | |
### @version $Id: eshell.sh 258 2012-09-13 15:18:18Z jzielke $ | |
########################################################################### | |
# Options are ramfs, tmpfs | |
# tmpfs can be swapped, ramfs will not be swapped | |
TYPE=ramfs | |
# These are used for creating and locating the permanent RAM disk | |
PERM_DIR=/mnt/eshell | |
PERM_BB=/bin/busybox | |
echo | |
make_ramdisk() { | |
echo 'Calculating space' | |
read SIZE < <("$1" du "$1") | |
SIZE="${SIZE%% $1}" # That is a tab | |
# Provide a few k for wiggle room | |
SIZE=$[SIZE+9] | |
read ID < <("$1" id -u) | |
echo 'Creating '$SIZE'k RAM disk in '$2 | |
if [ $ID -eq 0 ]; then | |
"$1" mount -t "$TYPE" -o size=${SIZE}k,mode=755 "$TYPE" "$2" | |
else | |
sudo "$1" mount -t "$TYPE" -o size=${SIZE}k,mode=755,uid=$ID "$TYPE" "$2" | |
if [ "$TYPE" == "ramfs" ]; then | |
sudo "$1" chown "$ID" "$2" | |
fi | |
fi | |
} | |
make_env() { | |
"$1" cp "$1" "$2/busybox" | |
echo 'Creating .profile' | |
echo alias rootsh=\'sudo env PATH=\"\$PATH\" busybox ash\' >"$2/.profile" | |
echo alias >>"$2/.profile" | |
echo echo \'exit to cleanup\' >>"$2/.profile" | |
echo echo \'rootsh for a root shell\' >>"$2/.profile" | |
echo echo >>"$2/.profile" | |
echo 'Building symlinks' | |
cd "$2" | |
{ { ./busybox --list 2>/dev/null; } || { ./busybox --help | ./busybox sed -n '/Currently defined functions:/,$p' | ./busybox grep -v 'Currently defined functions:' | ./busybox tr -d ' \t\n' | ./busybox tr , '\n' | ./busybox grep -v 'busybox'; }; } | ./busybox xargs -n 1 ./busybox ln -s busybox | |
} | |
setup_eshell() { | |
# Check if RAM disk is already mounted | |
read OUTPUT < <($PERM_BB grep -- "$PERM_DIR" /proc/mounts) | |
if [ -z "$OUTPUT" ]; then | |
echo 'Creating eshell RAM disk' | |
"$PERM_BB" mkdir -p "$PERM_DIR" | |
make_ramdisk "$PERM_BB" "$PERM_DIR" | |
fi | |
make_env "$PERM_BB" "$PERM_DIR" | |
} | |
check_tty () { | |
echo 'Checking for tty' | |
"$1" tty >/dev/null | |
if [ $? -ne 0 ]; then | |
echo 'No tty found, did you mean to ssh -t ?' | |
echo 'Press ctrl-c to stop or enter to continue' | |
read JUNK | |
fi | |
} | |
check_fallback() { | |
read OUTPUT < <("$1" true 2>&1 >&-) | |
if [ "$OUTPUT" == 'Using fallback suid method' ]; then | |
echo 'To suppress "Using fallback suid method" warnings, as root:' | |
echo 'touch /etc/busybox.conf' | |
echo | |
fi | |
} | |
run_eshell() { | |
check_fallback "$1/busybox" | |
cd / | |
export PATH="$1:$PATH" | |
echo 'Starting shell' | |
ENV="$1/.profile" "$1/busybox" ash | |
echo | |
} | |
show_help() { | |
echo 'eshell creates a BusyBox emergency shell in RAM. | |
There are 3 ways to use eshell. | |
1) eshell | |
Without any parameters: | |
This will set your PATH and run busybox ash as your shell. | |
If a permanent RAM disk was previously setup it will be used. | |
sudo access is required if the permanent RAM disk is not already set up. | |
sudo is not part of busybox. Run rootsh to sudo to root and retain | |
the eshell PATH. | |
2) eshell <busybox> | |
With the path to busybox as the parameter: | |
This is useful if you have downloaded busybox and it is not in your path | |
or you want to use a binary other than the first busybox in your path. | |
If the path to busybox is provided the permanent shell will not be used. | |
3) eshell setup | |
This will setup eshell in '$PERM_DIR' for later use. | |
Run eshell setup from your system startup scripts. | |
' | |
check_fallback busybox | |
} | |
if [ "$1" == '--help' -o "$1" == '-h' ]; then | |
show_help | |
exit | |
elif [ "$1" == "setup" ]; then | |
setup_eshell | |
exit | |
elif [ $# -eq 0 -a -e "$PERM_DIR/busybox" ]; then | |
echo 'Using permanent RAM disk in '$PERM_DIR | |
check_tty "$PERM_DIR/busybox" | |
run_eshell "$PERM_DIR" | |
exit | |
elif [ $# -eq 0 ]; then | |
echo 'Locating busybox' | |
read BB < <(command -v busybox) | |
else | |
echo 'Using '$*' for busybox binary' | |
BB="$*" | |
fi | |
if [ -n "$BB" ]; then | |
# Should check that $BB is actually a busybox binary | |
check_tty "$BB" | |
echo 'Creating temp directory' | |
read TMPDIR < <($BB mktemp -td 2>/dev/null || $BB mktemp -d /tmp/tmp.XXXXXX) | |
make_ramdisk "$BB" "$TMPDIR" | |
make_env "$BB" "$TMPDIR" | |
run_eshell "$TMPDIR" | |
echo 'Cleaning up' | |
sudo "$BB" umount "$TMPDIR" | |
"$BB" rmdir "$TMPDIR" | |
else | |
echo >&2 | |
echo 'Error: Could not find busybox in '$PATH >&2 | |
echo 'Rerun '$0' providing the path to busybox as an argument' >&2 | |
echo 'Use -h or --help for help' >&2 | |
echo >&2 | |
exit 1 | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Summary
This script creates an emergency shell using a RAM Disk and BusyBox. This is useful when your system is heavily loaded due to disk I/O. If it takes a few minutes between commands and you just want to run top and then kill <pid> having some utilities in RAM can help.
Prerequisites
sudo access.
Bash. This script currently uses some bashisms and expects to find bash in /bin.
Kernel with ramfs or tmpfs enabled.
BusyBox. I strongly suggest a statically compiled binary. Your distribution probably provides such a package. It may be called busybox or busybox-static.
You can check your binary with the file command:
/bin/busybox: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for GNU/Linux 2.6.15, stripped
You are looking for the words 'statically linked'.
Install
Download eshell.sh
Rename it:
mv eshell.sh eshell
Make it executable:
chmod +x eshell
Change ownership:
sudo chown root:root eshell
Put it in your path:
sudo mv -i eshell /usr/local/bin/
Optionally run eshell setup as root:
sudo eshell setup
eshell setup
You can pre-load eshell by running eshell setup. This may be worth running on boot. It will permanently1 use RAM but it is in the neighborhood of 2M. This is definitely worth doing if you are going to have more than 1 eshell running at the same time.
eshell setup will create the RAM Disk, copy busybox to it, make the symbolic links, and then exit. It will not modify the path or run a shell.
These two variables are defined near the top of the script.
PERM_DIR defines the default location for the permanent shell while PERM_BB is the path to busybox. Change these if you need to. eshell setup does not search your path for the busybox binary.
Usage
When you need an emergency shell just run eshell. If a permanent shell is not set up, eshell will use the first busybox found in your path.
If you are remotely connecting and the system is under heavy load, you may want to bypass the shell profile scripts. One way to do that is to run eshell from the ssh command line. If you do that you need to tell ssh to allocate a tty with the -t parameter.
ssh -t user@host eshell
Since sudo is not part of busybox it has to be read from the disk. It may be better to use sudo once to become root instead of incurring that delay each time you need to run a command as root. To help with this, rootsh is a command in eshell that will use sudo to switch to root while retaining your modified path.
If busybox is not in your path or you wish to use a specific copy, you can provide the full path to the binary as a parameter to eshell. This bypasses the check for the permanent eshell.
eshell /home/user/Downloads/busybox-static-1.13.3
Problems
On older installs, you may see the following warning after every command: "Using fallback suid method". This warning can be suppressed by creating /etc/busybox.conf. This file can be empty.
sudo touch /etc/busybox.conf
Details
This script will create a RAM Disk, copy busybox to it, make the symlinks, change your path to prefer the RAM Disk busybox versions of the utilities, and run busybox ash. If a 'permanent' eshell is available your path is set and then ash is run. For speed, this script only uses builtin bash commands, busybox, and sudo.
Notes
1 Permanently is being used to differentiate RAM Disks that are removed when you exit eshell as compared to RAM Disks that continue to exist after you exit eshell. Neither option will continue to exist after a reboot.