Debian Android with no Root

I am running Debian Linux on my Android system. For ref: see Running Debian Armhf alongside Android

The Android device needs to be rooted in order to run Debian. Only root user can mount the debian.img

The steps described below is to allow a user to run Debian Linux without using a root account, and to unroot Android.

It depends on whether the Android system is running /system/bin/sdcard after it boots up, the virtual sdcard daemon. If the sdcard daemon is not running, the below steps are not valid.

I have tested the below setup on only Android 4.3 & 4.4. (Warning: use it at your own risk!)

Assumption is made here that one have already setup a user account in Debian that one can use to login and use the system. That user account will require sudo access, for otherwise one will be unable to do any admin tasks like installing Debian packages. For ref: see Android X Server for how I access Debian on my Android.

In addition, one may want to install a custom recovery image, so that one can re-root the Android easily if the need arise.


First, I move debian.img file from the sdcard to the Debian kit path at /data/local/deb

Now, to mount /data/local/deb/debian.img will require a small change in /data/local/deb/bootdeb

This is to change the image path using the IMG variable: below, the original IMG is commented and the new IMG is added.

/data/local/deb/bootdeb

1     #IMG=${EXTERNAL_STORAGE:-/sdcard}/debian.img
2 IMG=${BIN}/debian.img
3

To help debugging, add this:

1     export DEB_DEBUG=true 
2

Add 'export CUSTOM_ROM=true' if the following symlinks are used by your ROM: /etc -> /system/etc, /lib -> /system/lib

1     export CUSTOM_ROM=true
2

Second, is to prepare the custom script to mount the debian.img when the device starts, and also to unmount it when the device shutdown or reboot. All these scripts are placed at /data/local/home

As root user, creates the /data/local/home dir

1     mkdir /data/local/home
2 cd /data/local/home
3

Add/create the /data/local/home/opt_mount script as:

/data/local/home/opt_mount

 1     #!/system/bin/sh
2
3 host="your-hostname"
4
5 # once only
6 # hostname
7 if [ "$(/system/bin/getprop net.hostname)" = "$host" ]; then
8 echo "net.hostname is already set"
9 else
10 /system/bin/setprop net.hostname "$host"
11
12 # deb
13 if [ -d /usr ]; then
14 echo "deb is mounted?"
15 else
16 /system/bin/setenforce 0
17 /data/local/deb/bootdeb s
18 echo "start opt_mount." >> /data/local/home/sdcard.log
19 /bin/chgrp fuse /dev/fuse
20 /bin/chmod g+rw /dev/fuse
21 fi
22 fi
23

Basically, this opt_mount script is used to execute a one-time setup when the device boots up. It uses the hostname property to check whether it is executed before. You should change the "your-hostname" to a name for your device. If the hostname is not set yet, the script sets it, then it will call the bootdeb script to mount the debian.img and run the sshd daemon. (openssh-server)

The next 2 lines are optional. It is to change the group of /dev/fuse to the fuse group, and allow the fuse group read/write access. This is needed if you want a normal user to use the FUSE file system

The setenforce 0 is needed on Android 4.4 where SELinux uses enforcing mode , otherwise the sshd will throw errors.

Add/create the /data/local/home/sdcard_deb script as:

/data/local/home/sdcard_deb

 1     #!/system/bin/sh
2 # pass to original sdcard
3
4 pipe=/data/local/tmp/stopdeb
5 sdlog=/data/local/home/sdcard.log
6
7
8 trap stop SIGTERM SIGINT
9
10 trap "rm -f $pipe" EXIT
11
12
13 function checkexit()
14 {
15 if [ ! -p $pipe ]; then
16 if [ ! -d /usr ]; then
17 echo "wait for sdcard" >> $sdlog
18 wait $pid
19 exit 0
20 fi
21 /usr/bin/mkfifo -m 666 $pipe
22 echo "created pipe" >> $sdlog
23 /etc/init.d/rc 2 >> $sdlog 2>&1
24 echo "init rc: 2" >> $sdlog
25 fi
26 # only stop when shutdown/reboot
27 while true
28 do
29 if read line <$pipe; then
30 if [ "$line" = 'exit' ]; then
31 shut=$(/system/bin/getprop sys.shutdown.requested)
32 echo "shutdown? $shut" >> $sdlog
33 [ "$shut" ] && stop
34 fi
35 fi
36 done
37 }
38
39 function stop()
40 {
41 /usr/bin/pkill -9 x.org.server
42 /bin/run-parts --regex '^S.*' --reverse --report -a stop /etc/rc2.d >> $sdlog 2>&1
43 /data/local/deb/bootdeb S
44 /data/local/deb/bootdeb u >> $sdlog 2>&1
45 num=10
46 while [ -d /data/local/mnt/usr ]; do
47 if [ $num -eq 0 ]; then
48 echo "give up stop deb." >> $sdlog
49 exit 0
50 fi
51 /data/local/deb/bootdeb u >> $sdlog 2>&1
52 $((num--))
53 done
54 echo "stop deb." >> $sdlog
55 exit 0
56 }
57
58 /data/local/home/opt_mount
59
60 /system/bin/sdcard_o "$@" > /dev/null 2>&1 &
61 pid=$(/usr/bin/pgrep sdcard_o)
62
63 checkexit
64

This sdcard_deb script is going to replace the /system/bin/sdcard daemon, so that it will be executed with root user when device boots up. The original /system/bin/sdcard will be renamed to /system/bin/sdcard_o

This script calls the opt_mount script to mount the debian.img and run the sshd daemon. (openssh-server) Next, it runs the original sdcard daemon, passing it all the arguments. Lastly, it calls its checkexit function which will check for the Android system shutdown with the aid from a helper Android app. Additionally, /etc/init.d/rc 2 is used to start the Linux services (at the default Debian runlevel 2)

If the Android device is shutting down or rebooting, it will call the stop function to kill the Android X Server, to stop all the Linux services (at runlevel 2), and to unmount the debian.img .

Add/create the /data/local/home/undeb script as:

/data/local/home/undeb

 1     #!/system/bin/sh
2
3 pipe=/data/local/tmp/stopdeb
4
5 if [ ! -p $pipe ]; then
6 echo "deb not running" >> /data/local/home/sdcard.log
7 exit 1
8 fi
9
10 echo "exit" >$pipe
11

This undeb script basically sends an exit message to the named pipe created by the sdcard_deb, to inform sdcard_deb to stop.

With the help of System Trigger Android app, by specifying /data/local/home/undeb as the command to execute on shutdown, it will execute /data/local/home/undeb command when the device shutdowns or reboots.

The System Trigger source code is released at https://github.com/skyleecm/systemtrigger

Optionally, add/create the /data/local/home/undeb_kill script as:

/data/local/home/undeb_kill

1     #!/system/bin/sh
2 /usr/bin/pkill -15 -uroot sdcard
3

The undeb_kill script sends the sigterm signal to sdcard_deb, which will also call its stop function and unmount the debian.img . You can use it to unmount manually with:

1     sudo /data/local/home/undeb_kill
2

Thirdly, is to replace and rename the system sdcard daemon:

1     mount -o remount,rw /system
2
3 mv /system/bin/sdcard /system/bin/sdcard_o
4 ln -s /data/local/home/sdcard_deb /system/bin/sdcard
5
6 mount -o remount,ro /system
7

After this, the Android device can be rebooted to test whether the debian.img is mounted on boot, and whether it is unmounted on shutdown. You should at least test it a few times.


The log file /data/local/home/sdcard.log should be similar to the below if the scripts are running without error:

 1     start opt_mount.
2 created pipe
3 stty: standard input: Inappropriate ioctl for device
4 Using makefile-style concurrent boot in runlevel 2.
5 Starting anac(h)ronistic cron: anacron.
6 Starting periodic command scheduler: cron.
7 Starting system message bus: dbus.
8 Starting web server: lighttpd.
9 saned disabled; edit /etc/default/saned
10 Starting OpenBSD Secure Shell server: sshd.
11 init rc: 2
12 shutdown? 0
13 /etc/rc2.d/S05sshfs:
14 Stopping sshfs:
15 /etc/rc2.d/S03saned:
16 saned disabled; edit /etc/default/saned
17 /etc/rc2.d/S02ssh:
18 Stopping OpenBSD Secure Shell server: sshd.
19 /etc/rc2.d/S02rsync:
20 Stopping rsync daemon: rsync.
21 /etc/rc2.d/S02lighttpd:
22 Stopping web server: lighttpd.
23 /etc/rc2.d/S02dbus:
24 Stopping system message bus: dbus.
25 /etc/rc2.d/S02cron:
26 Stopping periodic command scheduler: cron.
27 /etc/rc2.d/S02anacron:
28 Stopping anac(h)ronistic cron: anacron.
29 umount /bin
30 umount /boot
31 umount /etc
32 umount /home
33 umount /lib
34 umount /media
35 umount /opt
36 umount /root
37 umount /run
38 umount /sbin
39 umount /selinux
40 umount /srv
41 umount /tmp
42 umount /usr
43 umount /var
44 umount /data/local/mnt
45 mount -o remount,ro /
46 stop deb.
47 wait for sdcard
48 start opt_mount.
49 created pipe
50 . . .
51 init rc: 2
52

Playing video issue:

If there is a problem playing video, like youtube doesn't work. And if it is caused by "unable to open media codecs configuration xml file.", then its because Android cannot access the /etc/media_codecs.xml file. - See MediaCodecList.cpp

When Debian kit mounts, it creates a link in /etc/media_codecs.xml to point to its source. It seems the Android cannot open this link. This problem is fixed by copying the source file to the Linux /etc (the etc dir mounted by Debian kit)

1     sudo cp /system/etc/media_codecs.xml /etc/media_codecs.xml
2

Lastly, if everything is ok, then we can now unroot the Android device.

I am using SuperSU

Launch SuperSU, click on Settings menu, then click on Full unroot. Once you reboot your device, you cannot run su anymore.

Now, we have Debian on Android with no Root.

Comments

blog comments powered by Disqus