#!/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