Make mounted cifs/smb share visible for normal user in Android-x86

  • With ES Explorer not to be trusted any more, I needed another solution for easy access to my SMB/CIFS network shares. Mounting a SMB/CIFS network share in Android-x86 (version 9 R2) turned out to be a lot easier than any of the solutions I found on StackExchange. I did not need to install any software or app, mount -t cifs works just out of the box.

    The problem is that I cannot make this mount visible for normal user. Only root or superuser, whatever it is called in Android, sees and can use the mounted file system, whereas the normal user keeps seeing the mountpoint as a directory of Android's own filesystem.

    To clarify, have a look at this terminal session. In this example, Android is running in a Virtual Box VM, the IP address is that of the host itself. I make a subdirectory in /sdcard/Download/ to mount on, with the intent of easily moving files from Download to the share mounted on that subdirectory. I mount the share as superuser, with appropriate options, and then, both as normal and as super user, list the subdirectory contents and stat the subdirectory :

    $ cd "/$EXTERNAL_STORAGE"/Download/ # i.e. /sdcard/Download/
    $ mkdir SERVER_SHARE
    $ touch SERVER_SHARE/"NOT THE MOUNTED SHARE" # a marker for the base directory
    $ su -c "mount -v -o username=guest,rw,noperm,iocharset=utf8 -t cifs // $PWD/SERVER_SHARE"
    $ ls SERVER_SHARE/
    $ su -c "ls SERVER_SHARE"
    ... lists all the files on the share ...
    $ stat SERVER_SHARE
      Size: 4096        Blocks: 0          IO Block: 512   directory
    Device: 1dh/29d Inode: 409629          Links: 2
    Access: (0770/drwxrwx---)  Uid: ( 0/    root)   Gid: ( 9997/everybody)
    $ su -c "stat SERVER_SHARE"
      Size: 0           Blocks: 0          IO Block: 512   directory
    Device: 1eh/30d Inode: 217          Links: 2
    Access: (0755/drwxr-xr-x)  Uid: ( 0/    root)   Gid: ( 0/    root)

    You see the difference between normal and super user: ls shows different directory contents because stat says they see the subdirectory on a different Device. A possible explanation could be that the normal user has the file descriptor for the directory open, and keeps using that file descriptor and the contents it points to, even after some other file system is mounted over it. But that would probably not explain why exactly the same thing happens if I put the mkdir inside the su command for the mount.

    For the time being, I can only access the mounted samba share of the VM host from the terminal, as super user, to copy files between the share and the Download folder. I have put the mkdir and mount commands in a script, and added the touch command to mount the directory under the mountpoint as 'not the network share'.

    My question is this: how do I make the mounted share visible to the normal user, so that I can use the Android apps like "Files" and other file managers to access it in a GUI.

  • Management summary

    • You probably do not need this.
    • There are free (gratis, yes) apps to access network shares.
    • Mounting network shares does not even need these apps; everything you need is included with Android-x86.

    How to access your network shares as user of Android-x86

    • There are plenty of file manager apps that allow you to copy files between your Android directories and your network shares. One that I find particularly suitable for this is a free app called X-Plore File Manager, because in it you can set up shortcuts to your network shares, and it has a dual pane view, so that you can open source and destination directories each in their own pane.
    • However, to directly access network shares from within apps, without intermediation of a file manager, it is usefull to mount those network shares into Android's user visible folders like Downloads, Movies, Music or Pictures.
    • Though not really linux, one of the linuxy things Android-x86 uses to complicate life for the unsuspecting user, for her or his own good, is Security-Enhanced Linux or SELinux. It is straightforward to mount a network share, there is nothing to install. But you need the appropriate security context to mount a network share so that it is visible to you as user.
    • To make things reproducible, you can script the mounting procedure. Android-x86 comes with a stripped MirBSD Korn shell. You can read it's online.
    • You can use my script as example; I clarified it with comments. In this script, fill in your own servername and server's ip address, and maybe the share name you use most; mine is named RAMDISK, which is ... a ramdisk.
    • Because my Androix-x86 device is not accessible for others, I hard coded my username and password. I hope you can not retrieve my original answer after I modified it to hide myusername and mypassword. You probably prefer not to code your credentials in a script; you can use the shell's builtin read command to enter them on the command prompt.
    main() {
        # default to my preferred share
     typeset share="${1:-RAMDISK}"
        # MY SERVER
     typeset servername=MYSRV
     typeset serverip=
        # SELinux context for the virtual filesystem sdcardfs:
     typeset context="context=u:object_r:sdcardfs:s0,iocharset=utf8"
        # mount (from root mount namespace) to /mnt/runtime/write/emulated which is
        # propagated to all apps' mount namespaces.
     typeset mntpt=/mnt/runtime/write/emulated/0/Download/"$servername"_"$share"
        # make mountpoint and add file as warning: if you see that file,
        # you do not see the network share
     [ -d "$mntpt" ] || su -c "mkdir -p \"$mntpt\" ; \
        touch \"$mntpt\"/\" @=# NOT A MOUNTED NETWORK SHARE #=@. \""
        # first try to mount with my credentials, used as file ownership on server, else as guest
        # su not needed when already running as su, but does no harm either
     su -c "mount -v -o username=myuser,password=mypassword,rw,noperm,$context \
        -t cifs //$serverip/\"$share\" \"$mntpt\" || \
       mount -v -o username=guest,ro,noperm,$context \
        -t cifs //$serverip/\"$share\" \"$mntpt\" || \
       echo mount of \"\" failed"
     unset -f main
    main "$@"
    • I saved this script on my Android-x86 device as /sdcard/mounty. SELinux makes it tricky to make it executable, but that is not needed: you can let the shell's builtin commands source or . execute it. From a terminal app, or after pressing Alt-F1 to go to the tty1 terminal (Alt-F7 brings you back to the GUI), just enter
    . /sdcard/mounty MYSHARENAME
    • Instead of a mountpoint in .../Download/, you could mount your shared movies under /mnt/runtime/write/emulated/0/Movies/, and the network share with your family album under /mnt/runtime/write/emulated/0/Pictures/, of course.

    Technical details

    • You can read up on the reason why you need a SELinux context in to "How to bind mount a folder inside /sdcard with correct permissions?". I only understand half of it, but the gist is that under Android not only users, but apps too need access rights as well.
    • To implement this, a special file system called sdcardfs is used. It exposes the folders that a user sees under /sdcard, to the apps on 3 different mount points, depending on an app's access rights, and on 1 extra mount point for the user's access. This is an extract of what the mount command reports :
    /data/media on /mnt/runtime/default/emulated type sdcardfs (rw,...,gid=1015,multiuser,mask=6)
    /data/media on /mnt/runtime/read/emulated type sdcardfs (rw,...,gid=9997,multiuser,mask=23)
    /data/media on /mnt/runtime/write/emulated type sdcardfs (rw,...,gid=9997,multiuser,mask=7)
    /data/media on /storage/emulated type sdcardfs (rw,...,gid=1015,multiuser,mask=6)
    • The /read/ and /write/ mountpoints speak for themselves.
    • I guess that the /default/ mountpoint is for navigating through directories only, for apps with neither read nor write access.
    • Exploring the directory tree with the command ls -l, you find directory /storage/emulated/ holding a subdirectory for each user. In single user installations this will be user 0, wherein you will find the user directories Download, Movies etc. When user 0 logs in, his /storage/emulated/0/ is mirrored onto /storage/self/primary/.
    • Directory /sdcard/ finally is, in fact, a symbolic link to that /storage/self/primary/, and voilà, that is why the user sees his user directories under /sdcard/, which is all a non-root user gets to see of his filesystem.
    • Mounting the network share, with the right SELinux context, onto a directory under /mnt/runtime/write/emulated/0/ (note the write directory), as in my script, makes the share visible somewhere under the same 4 directories:
    // on /mnt/runtime/default/emulated/0/Download/FRT_RAMDISK type cifs (rw,...
    // on /mnt/runtime/read/emulated/0/Download/FRT_RAMDISK type cifs (rw,...
    // on /mnt/runtime/write/emulated/0/Download/FRT_RAMDISK type cifs (rw,...
    // on /storage/emulated/0/Download/FRT_RAMDISK type cifs (rw,...

Suggested Topics