Skip to content

Instantly share code, notes, and snippets.

@JackZielke
Created Feb 20, 2022
Embed
What would you like to do?
Create a BusyBox based Emergency Shell
#!/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
@JackZielke
Copy link
Author

JackZielke commented Feb 20, 2022

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:

    $ file `which busybox`
    

    /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.

# These are used for creating and finding the permanent RAM disk
PERM_DIR=/mnt/eshell
PERM_BB=/bin/busybox

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.

@JackZielke
Copy link
Author

JackZielke commented Feb 20, 2022

Archive.org version of the original page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment