Monday, October 29, 2018

External hard drive file share on Nvidia Shield with FUSE/SSHFS

I recently picked up a 2nd gen Nvidia Shield (not-pro).  It's slightly smaller than the first gen and has a few less ports...
Image result for nvidia shield 2017
Unlike the pro version it only has 16 GB of internal storage.  No problem, I'll just plug in an external USB hard drive and use the native CIFS service.  Only now there is a problem:  For whatever reason only the internal storage can be accessed via CIFS not the external storage.

I am not wedded to CIFS so I started looking around for alternatives.  
  • First I went down a rabbit hole looking at FTP Android services.  These are easy to get going.  But to get access to the external storage I was going to need to root the device.  Sure I could do that, but I don't want too.  
  • Then I came across a few Internet posts pointing towards SSHelper.  Basically it is a user space SSH service.  That should come in handy even if it couldn't access the external storage (spoiler: it can)
SSHelper is not on the Android TV store.  We need to "sideload" for it to be installed.  Which sounds dodgy but it isn't. probably.  In any case it is tricky and there's a few different methods.  I chose to use the network ADB method.  To make this easier someone has published a GUI frontend, NSTV v0.14.

There was a few gotchas so I'll just summarise the sequence :
    • Unplug the USB hard drive, and
    • Disable all the settings in Android Settings > Storage.
  • Then I tried to use NSTV to sideload the SSHelper package:
    • A command prompt would appear and instantly error with some kind of file not found issue.  This turned out to be a red herring
    • It couldn't initially connect.  I ended up working around this by starting a cmd.exe and running the adb connect command manually i.e. adb connect 192.168.1.2 (the Shield IP)
  • Now installed, but I couldn't see it anywhere in the interface.  But I found an Android TV store app that helps called Sideload Channel.  Using Sideload Channel I was able to launch SSHelper and configure the password
At this point I was able to SSH to the device, success!  Note that because it is in user space it doesn't listen on the standard SSH port (22).  So we need to specify the port in the ssh client (-p 2222).  

Now onto the external hard drive.  Using ADB I worked out that storage devices can be found in /storage.  With SSH we don't get permission to see the root folder (/), so you cannot find it by tabbing or the like.  Also my external hard drive came up with a strange identifier.  Yours will of course be different:

u0_a100@localhost:~$ ls -l /storage
total 32
drwxr-xr-x    1 root     everybod     28672 Oct 27 13:19 30D4A05DD4A026D6
drwx--x--x    4 root     everybod      4096 Jan  1  2013 emulated
drwxr-x--x    2 root     root            60 Oct 22 17:08 self

For security reasons write access has been disabled to the external drive except for one special folder that was already created, NVIDIA_SHIELD.  I suspect this got created when I was fiddling with the settings in Android Settings > Storage.

u0_a100@localhost:NVIDIA_SHIELD$ cd /storage/30D4A05DD4A026D6/
u0_a100@localhost:30D4A05DD4A026D6$ touch t
touch: t: Permission denied
u0_a100@localhost:30D4A05DD4A026D6$ cd /storage/30D4A05DD4A026D6/NVIDIA_SHIELD/
u0_a100@localhost:NVIDIA_SHIELD$ touch t
u0_a100@localhost:NVIDIA_SHIELD$

So we almost have lift off.  Now we just need to access it like a file share.  That's where FUSE/SSHFS comes in.  Under Ubuntu Linux you just need to do a few steps:

Step 1. Install FUSE/SSHFS

ubuntu# apt-get install sshfs fuse

Step 2.  Create an entry in fstab

The fstab entry options we need are not immediately obvious.  In the end my entry looks like this:

sshfs#root@192.168.1.2:/storage/30D4A05DD4A026D6/NVIDIA_SHIELD /mnt/shield fuse defaults,allow_other,port=2222,noatime,IdentityFile=/home/matthewh/.ssh/id_rsa 0 0

The not so obvious options are:
  • port=2222.  Yes this sounds obvious but I found little referencing it with Google.  
  • noatime.  Rsync would error out when trying to set atime and abort transfers.  This is likely due to having limited privileges in SSHelper.
  • IdentityFile=/blah/blah.  This is the private key used for authentication.  I won't go into detail on how to setup private key authentication.  Basically it works just like any other Linux host.
There you have it.  An external hard drive file share on Nvidia Shield using FUSE/SSHFS!