Last active
July 24, 2016 15:19
-
-
Save enten/63cedaca9bf019feb71a to your computer and use it in GitHub Desktop.
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
#!/system/bin/sh | |
set -u | |
## ======================================================================================== | |
## alfred : manages an ArchLinux rootfs for enable LXC usage on Android | |
## ======================================================================================== | |
PROGNAME="alfred" | |
PROGVERS="0.0.6" | |
PROGCONF="/data/$PROGNAME" | |
PROGHELP="Usage: $PROGNAME [cmd] | |
Setup commands: | |
install <path> # Install alfred under <path> | |
uninstall # Uninstall alfred | |
" | |
PROGPATH= | |
PROGTREE= | |
## ---------------------------------------------------------------------------------------- | |
## Environment | |
## ---------------------------------------------------------------------------------------- | |
SMOUNT_BIN="/data/cloudlet/smount" | |
BUSYBOX_BIN="/system/bin/busybox" | |
BUSYBOX_APPLETS="awk basename chroot grep head rdate tar wget" | |
NTP_SERVER="ntp.unice.fr" | |
ROOTFS_IMG_SRC="http://archlinuxarm.org/os/ArchLinuxARM-armv7-latest.tar.gz" | |
ROOTFS_IMG_DIST="archlinux" | |
ROOTFS_IMG_RELEASE="latest" | |
ROOTFS_IMG_ARCH="armv7" | |
ROOTFS_IMG_NAME= | |
ROOTFS_IMG_PATH= | |
AUTO_ACCEPT= | |
BAD_CONFIG= | |
READ= | |
ROOTFS_INIT=$(cat <<EOF | |
rm -f /etc/resolv.conf | |
echo "nameserver 8.8.8.8" > /etc/resolv.conf | |
pacman -Syu --noconfirm | |
pacman -S --noconfirm git lxc wget | |
echo "Bye!" | |
EOF | |
) | |
## ---------------------------------------------------------------------------------------- | |
## Main functions | |
## ---------------------------------------------------------------------------------------- | |
main() { | |
checkSystem | |
[ $# -lt 1 ] && notfound | |
local cmd=$1; shift | |
case $cmd in | |
help) | |
echo "$PROGHELP" | |
exit | |
;; | |
mount|umount) | |
[ 0 -lt $# ] && notfound | |
checkInstall | |
cmd=$cmd"Rootfs" | |
$cmd | |
;; | |
install|uninstall) | |
[ "$cmd" = "uninstall" ] && checkInstall | |
$cmd $@ | |
;; | |
*) | |
checkInstall | |
run $cmd $@ | |
;; | |
esac | |
} | |
install() { | |
[ $# -lt 1 ] && notfound | |
[ 2 -lt $# ] && notfound | |
[ 1 -lt $# ] && [ "$2" = "auto-accept" ] && AUTO_ACCEPT=1 | |
[ "$PROGPATH" != "" ] \ | |
&& error "FAILED! Alfred is already installed under path $PROGPATH" \ | |
&& warn "You must REMOVE IT FIRST with 'alfred uninstall'" | |
#&& fail "You must REMOVE it with 'alfred uninstall'" | |
PROGPATH=$1 | |
[ "${PROGPATH:0:1}" != "/" ] && PROGPATH="$(pwd)/$PROGPATH" | |
echo "Alfred will be INSTALLED under the path $PROGPATH" | |
confirm "Are you sure? [y/N]" | |
installWizard | |
echo "Done!" | |
} | |
uninstall() { | |
[ 1 -lt $# ] && notfound || [ 0 -lt $# ] && [ "$1" = "auto-accept" ] && AUTO_ACCEPT=1 | |
echo "Alfred installation under the path $PROGPATH will be REMOVED" | |
confirm "Are you sure? [y/N]" | |
umountRootfs | |
rm -fr $PROGPATH >/dev/null 2>&1 | |
rm -f $PROGCONF >/dev/null 2>&1 | |
echo "Done!" | |
} | |
run() { | |
[ "$BAD_CONFIG" = "1" ] && fail "FAILED! Check your file configuration $PROGCONF" | |
mountRootfs | |
local cmd="/bin/bash" | |
[ 0 -lt $# ] && cmd="$@" | |
beforeRunning $cmd | |
changeRoot "$cmd" | |
afterRunning $cmd | |
} | |
## ---------------------------------------------------------------------------------------- | |
## Support functions | |
## ---------------------------------------------------------------------------------------- | |
warn() { | |
echo $@ >&2 | |
} | |
error() { | |
echo $@ 1>&2 | |
} | |
fail() { | |
[ 0 -lt $# ] && error $@ | |
exit 1 | |
} | |
notfound() { | |
error "ERROR: command not found" | |
echo "--" | |
echo "$PROGHELP" | |
fail | |
} | |
checkBusybox() { | |
[ ! -e "/system/bin/adb" ] && return | |
if ! type $BUSYBOX_BIN >/dev/null 2>&1; then | |
echo "FAILED! This program needs busybox to work" 1>&2 | |
exit 1 | |
fi | |
for i in $BUSYBOX_APPLETS; do | |
eval "alias '$i=$BUSYBOX_BIN $i'" | |
done | |
} | |
checkConfig() { | |
[ -e $PROGCONF ] && . $PROGCONF | |
[ "$PROGPATH" != "" ] && [ ! -e $PROGPATH ] && PROGPATH= && BAD_CONFIG=1 | |
for i in $PROGTREE; do | |
[ ! -e "$PROGPATH/$i" ] && BAD_CONFIG=1 && break | |
done | |
[ "$BAD_CONFIG" = "1" ] && warn "WARN! Verify your installation under $PROGPATH" | |
} | |
checkSystem() { | |
checkBusybox | |
checkConfig | |
[ $(date +%Y) -lt 2000 ] && rdate -s $NTP_SERVER | |
[ ! -e "/etc/resolv.conf" ] && echo "nameserver 8.8.8.8" > /etc/resolv.conf | |
} | |
checkInstall() { | |
[ "$PROGPATH" = "" ] && fail "FAILED! Alfred is not installed yet" | |
} | |
prompt() { | |
[ 0 -lt $# ] && echo -n "$@ " | |
read PROMPT | |
} | |
confirm() { | |
[ "$AUTO_ACCEPT" = "1" ] && return | |
prompt $@ | |
case $PROMPT in | |
[yY][eE][sS]|[yY]) | |
PROMPT=1 | |
;; | |
*) | |
fail "Cancelled." | |
;; | |
esac | |
} | |
downloadFile() { | |
if [ ! -e "$2" ]; then | |
if ! wget -q $1 -O $2; then | |
rm -f $2 >/dev/null 2>&1 | |
return 1 | |
fi | |
[ ! -e "$2" ] && return 1 | |
fi | |
return 0 | |
} | |
unpackArchive() { | |
if ! tar --numeric-owner -xf $1 -C $2 >/dev/null 2>&1; then | |
return 1 | |
fi | |
return 0 | |
} | |
writeConfig() { | |
echo "$1=\"$2\"" >> $PROGCONF | |
} | |
updateConfig() { | |
[ -e "$PROGCONF" ] && rm -f $PROGCONF >/dev/null 2>&1 | |
touch $PROGCONF >/dev/null 2>&1 | |
writeConfig "PROGPATH" $PROGPATH | |
writeConfig "PROGTREE" "$PROGTREE" | |
} | |
installWizard() { | |
echo -n "[1/5] Creating the install directory... " | |
if ! mkdir -p $PROGPATH >/dev/null 2>&1; then | |
fail "KO" | |
fi | |
echo "ok" | |
echo -n "[2/5] Donwloading the rootfs image... " | |
ROOTFS_IMG_NAME="$ROOTFS_IMG_DIST-$ROOTFS_IMG_RELEASE-$ROOTFS_IMG_ARCH-rootfs.tar.gz" | |
ROOTFS_IMG_PATH="$PROGPATH/$ROOTFS_IMG_NAME" | |
if ! downloadFile $ROOTFS_IMG_SRC $ROOTFS_IMG_PATH; then | |
fail "KO" | |
fi | |
echo "ok" | |
echo -n "[3/5] Unpacking the rootfs image... " | |
if ! unpackArchive $ROOTFS_IMG_PATH $PROGPATH; then | |
fail "KO" | |
fi | |
PROGTREE= | |
for i in $(find $PROGPATH -maxdepth 1 -type d); do | |
i=$(basename $i) | |
[ "$i" = "$(basename $PROGPATH)" ] && continue | |
[ -z "$PROGTREE" ] && PROGTREE=$i && continue | |
PROGTREE="$PROGTREE $i" | |
done | |
if ! updateConfig >/dev/null 2>&1; then | |
fail "KO" | |
fi | |
echo "ok" | |
echo -n "[4/5] Configuring the rootfs... " | |
echo "$ROOTFS_INIT" > $PROGPATH/rootfs.init | |
chmod 755 $PROGPATH/rootfs.init >/dev/null 2>&1 | |
if ! run "/rootfs.init" >/dev/null 2>&1; then | |
fail "KO" | |
fi | |
rm -f $PROGPATH/rootfs.init >/dev/null 2>&1 | |
echo "ok" | |
echo -n "[5/5] Finalizing the installation... " | |
rm -f $ROOTFS_IMG_PATH >/dev/null 2>&1 | |
echo "ok" | |
} | |
execCmd() { | |
$@ >/dev/null 2>&1 | |
} | |
mountRootfs() { | |
execCmd $SMOUNT_BIN / rprivate | |
if ! grep -q " $PROGPATH " /proc/mounts; then | |
execCmd mount -o bind $PROGPATH $PROGPATH | |
fi | |
for i in acct dev dev/cpuctl dev/pts proc sys sys/fs/cgroup system; do | |
[ ! -d /$i ] && continue | |
if grep -q " $PROGPATH/$i " /proc/mounts; then | |
continue | |
fi | |
execCmd mkdir -p $PROGPATH/$i | |
execCmd mount -o bind /$i $PROGPATH/$i | |
done | |
for i in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do | |
if ! grep -q " $PROGPATH/$i " /proc/mounts; then | |
execCmd mkdir -p $PROGPATH/$i | |
execCmd $BUSYBOX_BIN mount -n -t cgroup -o $i cgroup $PROGPATH/$i | |
fi | |
done | |
} | |
umountRootfs() { | |
cgmanagerStop | |
for i in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do | |
execCmd umount $PROGPATH/$i | |
done | |
for i in system sys/fs/cgroup sys proc dev/pts dev/cpuctl dev acct; do | |
if ! grep -q " $PROGPATH/$i " /proc/mounts; then | |
continue | |
fi | |
execCmd umount $PROGPATH/$i | |
done | |
if grep -q " $PROGPATH " /proc/mounts; then | |
execCmd umount $PROGPATH | |
fi | |
} | |
changeRoot() { | |
local env="TERM=$TERM SHELL=/bin/bash USER=root USERNAME=root HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LD_PRELOAD=" | |
local envBackup="TERM=$TERM SHELL=$SHELL USER=$USER HOME=$HOME PATH=$PATH LD_PRELOAD=$LD_PRELOAD" | |
for i in $env; do export $i; done | |
$BUSYBOX_BIN chroot $PROGPATH $@ | |
for i in $envBackup; do export $i; done | |
} | |
beforeRunning() { | |
case $1 in | |
"lxc-start") cmdLxcStartPrevent "$@" ;; | |
esac | |
} | |
afterRunning() { | |
case $1 in | |
"lxc-create") cmdLxcCreateCallback "$@" ;; | |
esac | |
} | |
cgmanagerIsRunning() { | |
if [ $(changeRoot "ps -x" | grep -c cgmanager) -lt 2 ]; then | |
return 1 | |
fi | |
} | |
cgmanagerStart() { | |
if ! cgmanagerIsRunning >/dev/null 2>&1; then | |
changeRoot cgmanager --daemon | |
fi | |
} | |
cgmanagerStop() { | |
if cgmanagerIsRunning >/dev/null 2>&1; then | |
changeRoot kill $(changeRoot ps -x | grep cgmanager | head -n1 | awk '{print $1}') | |
fi | |
} | |
cmdLxcStartPrevent() { | |
cgmanagerStart | |
} | |
cmdLxcCreateCallback() { | |
local nameFound= | |
local containerName= | |
local containerPath= | |
for i in "$@"; do | |
[ "$nameFound" = "1" ] && containerName=$i && break | |
[ "$i" = "-n" ] && nameFound=1 | |
done | |
[ -z "$containerName" ] && return | |
containerPath=/var/lib/lxc/$containerName/rootfs | |
[ ! -d "$PROGPATH/$containerPath" ] && return | |
changeRoot chroot $containerPath passwd | |
} | |
## ---------------------------------------------------------------------------------------- | |
## One main to rule them all... | |
## ---------------------------------------------------------------------------------------- | |
main $@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment