[Android Software/Hacking General [Developers Only]] dk_zero-cool:
One of the fun things you can do on your Android device, is to play around with different ways of getting a real distro (Debian, Ubuntu etc.) working along side the Android system. There are several (A lot) of tutorials in here on how to do this, so this part will not be covered here. This thread only contains some scripts that will help make it easier working with the chroot.

Most of the scripts that comes with the endless pool of chroot tutorials, is only made to mount and unmount the distro image in the most simple way. But nothing that helps walking in and out of the chroot without mount/unmount, and nothing that takes different services, busy devices etc. into consideration.

The debian.sh script in this thread has many tasks. It will on execution check to see if the image is mounted or not. If the image is mounted, it will just enter the chroot. If not, it will mount the image and then enter the chroot. On exit it will provide you with the option of exiting the chroot or exit and unmount.

Also it provides 4 custom scripts that is placed and executed inside the chroot. One for mount, unmount, enter chroot, leave chroot. This makes it possible to control chroot services much easier.

The script debian.sh is executed using the command "debian". You can also unmount the chroot from within the android shell by executing "debian unmount" instead of entering the chroot and then exit choosing to unmount.

The unmount process has several and different unmount attempts in case of busy devices, running services etc. which will make sure that the chroot is successfully unmounted.

File:

/system/bin/debian

#!/system/bin/sh
su -c "/system/bin/debian.sh $@"

File:

/system/bin/debian.sh

#!/system/bin/sh

createLinuxBoot() {
if [ ! -f $FILESYSTEM ]; then
echo "Missing the $DIST filesystem image!"

return 0

elif [ ! -z "$(mount | grep "$MOUNTPOINT ")" ]; then
# If the loop device is already mounted, we do nothing.
echo " - $DIST is already mounted. Entering chroot..."

else
echo " - Executing mount proccess of $DIST..."

if [ ! -d $MOUNTPOINT ]; then
# Create the mount point if it does not already exist
busybox mkdir -p $MOUNTPOINT 2> /dev/null

if [ ! -d $MOUNTPOINT ]; then
echo "It was not possible to create the missing mount location ($MOUNTPOINT)!"

return 0
fi
fi

# Android places loop devices in /dev/block/ instead of root /dev/
# If there are none in /dev/ we create links between /dev/loopX and /dev/block/loopX so that losetup will work as it should.
if [ ! -e /dev/loop0 ]; then
for i in 0 1 2 3 4 5 6 7
do
# Create each block device
mknod /dev/loop$i b 7 $i
done
fi

# Android also placed the frame buffer in /dev/grapichs instead of /dev
if [ ! -e /dev/fb0 ]; then
mknod /dev/fb0 b 29 0
fi

# Locate the current loop device file
if [ ! -z "$(losetup | grep "$FILESYSTEM")" ]; then
# If the filesystem file is already attached to an loop device, we get the path to the device file.
loblk=$(losetup | grep "$FILESYSTEM" | cut -d ":" -f 1)
else
# If the filesystem file is not yet attached, we attach it.
loblk=$(losetup -f)
losetup $loblk $FILESYSTEM 2> /dev/null

# Make sure that the device was successfully attached to a loop device file
if [ -z "$(losetup | grep "$FILESYSTEM")" ]; then
echo "It was not possible to attach the $DIST filesystem to a loop device!"

return 0
fi
fi

# Mount the filesystem
mount $loblk $MOUNTPOINT 2> /dev/null

if [ ! -z "$(mount | grep "$MOUNTPOINT ")" ]; then
# Bind some Android dirs to the linux filesystem
for i in $MOUNT_BIND
do
# Bind the dirs if they are not already binded
if [ -z "$(mount | grep "$MOUNTPOINT/$i ")" ]; then
# Create any missing dirs in the mountpoint
if [ ! -d $MOUNTPOINT/$i ]; then
busybox mkdir -p $MOUNTPOINT/$i 2> /dev/zero
fi

mount --bind /$i $MOUNTPOINT/$i
fi
done

# FIX the "stdin: is not a tty" error in direct hadware case.
if [ -z "$(mount | grep "$MOUNTPOINT/dev/pts ")" ]; then
mount -t devpts devpts $MOUNTPOINT/dev/pts
fi

# For the network.
#sysctl -w net.ipv4.ip_forward=1
echo 1 > /proc/sys/net/ipv4/ip_forward

# Cleanup tmp folder.
rm -rf $MOUNTPOINT/tmp/*

else
echo "It was not possible to mount $DIST at the specified location ($MOUNTPOINT)!"

return 0
fi

if [ -f $MOUNTPOINT/etc/init.chroot/rc_mount.sh ]; then
# Execute the mount init file, if it exists
chroot $MOUNTPOINT /etc/init.chroot/rc_mount.sh
fi

echo " - $DIST was successsfully mounted. Entering chroot..."
fi

return 1
}

removeLinuxBoot() {
if [ -z "$(mount | grep "$MOUNTPOINT ")" ]; then
# If linux is not mounted, then do nothing.
echo " - $DIST is already unmounted. Exiting..."

else
echo " - Executing unmount process of $DIST..."

if [ -f $MOUNTPOINT/etc/init.chroot/rc_unmount.sh ]; then
# Execute the unmount init script, if it exist.
chroot $MOUNTPOINT /etc/init.chroot/rc_unmount.sh
fi

sync
# The sleep part is very important. It may take some time before /dev is no longer busy
# after executing some services in the rc_unmount.sh script.
sleep 1

# Make sure that we have an loop device file to use
if [ ! -z "$(losetup | grep "$FILESYSTEM")" ]; then
# Get the loop device file
loblk=$(losetup | grep "$FILESYSTEM" | cut -d ":" -f 1)

for i in $UMOUNT_BIND
do
# Unmount all binding dirs
if [ ! -z "$(mount | grep "$MOUNTPOINT/$i ")" ]; then
umount $MOUNTPOINT/$i 2> /dev/zero
fi
done

sync

# Unmount the device
# In most cases one umount attempt will be enough.
# However it may take up to 3 tries in order to make it work.
# It depends on the types of services running or has been running before unmounting.

umount $MOUNTPOINT 2> /dev/null && sleep 1 2> /dev/zero

if [ ! -z "$(mount | grep "$MOUNTPOINT ")" ]; then
sync
umount $MOUNTPOINT 2> /dev/null && sleep 1 2> /dev/zero
fi

# If the device could not be unmounted
if [ ! -z "$(mount | grep "$MOUNTPOINT ")" ]; then
echo " - Unable to unmount $DIST. Will attempt to kill attached processes..."

# Try to kill all processes holding the device
fuser -k -9 $loblk
sync

# Use umount with the -l option to take care of the rest
umount -l $MOUNTPOINT 2> /dev/null && sleep 1
fi

# Make sure the device has been successfully unmounted
if [ -z "$(mount | grep "$MOUNTPOINT ")" ]; then
# Try to detach the device from the loop device file
losetup -d $loblk 2> /dev/null

# Make sure that the device was successfully detached
if [ -z "$(losetup | grep "$FILESYSTEM")" ]; then
echo "$DIST has been successfully unmounted!"

else
echo "$DIST has been successfully unmounted, but was not able not detach the loop device!"
fi

else
echo "$DIST could not be successfully unmounted!"
fi

else
echo "Could not locate the loop device. $DIST was not unmounted!"
fi
fi
}

if [ -z "$EXPORTED" ]; then
export EXPORTED="TRUE"

# Basic needed variables
export TERM=linux
export HOME=/root
export USER=root
export LOGNAME=root
export UID=0
export SHELL=bash

# Here you can add all of the paths that should be binded. One list for mount and one reversed list for unmount.
export MOUNT_BIND="dev dev/pts dev/cpuctl proc sys sys/kernel/debug system d vendor acct sdcard cache sd-ext data"
export UMOUNT_BIND="dev/cpuctl dev/pts dev proc sys/kernel/debug d sys vendor acct sdcard cache sd-ext system data"

# Here you can change mount and image paths
export DIST="Debian" # The name of the distro. Is used for the messages.
export FILESYSTEM=/mnt/sdcard/debian.img # Path to the distro image file
export MOUNTPOINT=/data/debian # Path where the distro is to be mounted
fi

export OLDPATH=$PATH
export PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/root/bin:$PATH

if [ "$1" = "unmount" ]; then
removeLinuxBoot

else
createLinuxBoot

if [ $? -eq 1 ]; then
if [ -f $MOUNTPOINT/etc/init.chroot/rc_enter.sh ]; then
chroot $MOUNTPOINT /etc/init.chroot/rc_enter.sh
fi

chroot $MOUNTPOINT /bin/bash -i

if [ -f $MOUNTPOINT/etc/init.chroot/rc_leave.sh ]; then
chroot $MOUNTPOINT /etc/init.chroot/rc_leave.sh
fi

echo -n " - Type [Y] to unmount $DIST or random key to exit chroot ]# "

read ACTION

if [ "$ACTION" = "y" ] || [ "$ACTION" = "Y" ]; then
removeLinuxBoot
fi
fi
fi

# Restore the PATH variable when executing chroot
export PATH=$OLDPATH

By default debian.sh will look for /mnt/sdcard/debian.img and mount it at /data/debian

The script has build-in first-time-install functionality that will create missing directories etc. Just change the variable "FILESYSTEM" in debian.sh to the correct path and filename of your distro image, and it will handle the rest.

Chroot Init Scripts

Inside your chroot, you can create the directory /etc/init.chroot and create the fallowing files.

rc_mount.sh - Executed after mount

rc_unmount.sh - Executed before unmount

rc_enter.sh - Executed when entering chroot

rc_leave.sh - Executed when leaving chroot

Here are an example of a mount and unmount script used to control tightvncserver.

File: (chroot) /etc/init.chroot/rc_mount.sh

#!/bin/sh

# Make sure that the vncserver is completly stopped before starting.
if [ ! -f /tmp/.X11-unix/X1 ] && [ ! -f /tmp/.X1-lock ]; then
# Start vncserver
vncserver -geometry 800x480 :1

else
# This is in case something went wrong the last time
# it was shut down. Perhaps an uncomplete unmount.
vncserver -kill :1 2> /dev/zero
unset /tmp/.X11-unix/X1 2> /dev/zero 2> /dev/zero
unset /tmp/.X1-lock 2> /dev/zero 2> /dev/zero
vncserver -geometry 800x480 :1
fi

File: (chroot) /etc/init.chroot/rc_unmount.sh

#!/bin/sh

# Only stop this if it is started
if [ -f /tmp/.X11-unix/X1 ] || [ -f /tmp/.X1-lock ]; then
vncserver -kill :1

# Make sure that these are removed
unset /tmp/.X11-unix/X1 2> /dev/zero
unset /tmp/.X1-lock 2> /dev/zero
fi

Using these scripts, the VNC Server is started on chroot mount and stopped on chroot unmount. You can still leave and enter the chroot keeping the VNC Server running.