Got removable media mount detection working on Android.

Bionic has an amusing stub for `getmntent` that prints out
"FIX ME! implement getmntent()"

But, `/proc/mounts` is there, so I just parse it.
This commit is contained in:
Joey Hess 2013-05-04 16:04:17 -04:00
parent 41e6c1de9a
commit d35132810a
5 changed files with 37 additions and 9 deletions

View file

@ -300,6 +300,10 @@ driveList = mapM (gen . mnt_dir) =<< filter sane <$> getMounts
| dir == "/tmp" = False | dir == "/tmp" = False
| dir == "/run/shm" = False | dir == "/run/shm" = False
| dir == "/run/lock" = False | dir == "/run/lock" = False
#ifdef __ANDROID__
| dir == "/mnt/sdcard" = False
| dir == "/sdcard" = False
#endif
| otherwise = True | otherwise = True
#else #else
driveList = return [] driveList = return []

View file

@ -65,9 +65,9 @@ sshInputAForm hostnamefield def = SshInput
<*> aopt textField "Directory" (Just $ Just $ fromMaybe (T.pack gitAnnexAssistantDefaultDir) $ inputDirectory def) <*> aopt textField "Directory" (Just $ Just $ fromMaybe (T.pack gitAnnexAssistantDefaultDir) $ inputDirectory def)
<*> areq intField "Port" (Just $ inputPort def) <*> areq intField "Port" (Just $ inputPort def)
where where
#ifndef __ANDROID__
check_hostname = checkM (liftIO . checkdns) hostnamefield check_hostname = checkM (liftIO . checkdns) hostnamefield
checkdns t = do checkdns t = do
#ifndef __ANDROID__
let h = T.unpack t let h = T.unpack t
let canonname = Just $ defaultHints { addrFlags = [AI_CANONNAME] } let canonname = Just $ defaultHints { addrFlags = [AI_CANONNAME] }
r <- catchMaybeIO $ getAddrInfo canonname (Just h) Nothing r <- catchMaybeIO $ getAddrInfo canonname (Just h) Nothing
@ -79,8 +79,8 @@ sshInputAForm hostnamefield def = SshInput
Just [] -> Right t Just [] -> Right t
Nothing -> Left bad_hostname Nothing -> Left bad_hostname
#else #else
-- getAddrInfo currently broken on Android -- getAddrInfo currently broken on Android
return $ Right t check_hostname = hostnamefield -- unchecked
#endif #endif
check_username = checkBool (all (`notElem` "/:@ \t") . T.unpack) check_username = checkBool (all (`notElem` "/:@ \t") . T.unpack)

View file

@ -3,7 +3,7 @@
- Derived from hsshellscript, originally written by - Derived from hsshellscript, originally written by
- Volker Wysk <hsss@volker-wysk.de> - Volker Wysk <hsss@volker-wysk.de>
- -
- Modified to support BSD and Mac OS X by - Modified to support BSD, Mac OS X, and Android by
- Joey Hess <joey@kitenet.net> - Joey Hess <joey@kitenet.net>
- -
- Licensed under the GNU LGPL version 2.1 or higher. - Licensed under the GNU LGPL version 2.1 or higher.
@ -16,13 +16,18 @@ module Utility.Mounts (
getMounts getMounts
) where ) where
#ifndef __ANDROID__
import Control.Monad import Control.Monad
import Foreign import Foreign
import Foreign.C import Foreign.C
import GHC.IO hiding (finally, bracket) import GHC.IO hiding (finally, bracket)
import Prelude hiding (catch) import Prelude hiding (catch)
#include "libmounts.h" #include "libmounts.h"
#else
import Utility.Exception
import Data.Maybe
import Control.Applicative
#endif
{- This is a stripped down mntent, containing only {- This is a stripped down mntent, containing only
- fields available everywhere. -} - fields available everywhere. -}
@ -32,6 +37,8 @@ data Mntent = Mntent
, mnt_type :: String , mnt_type :: String
} deriving (Read, Show, Eq, Ord) } deriving (Read, Show, Eq, Ord)
#ifndef __ANDROID__
getMounts :: IO [Mntent] getMounts :: IO [Mntent]
getMounts = do getMounts = do
h <- c_mounts_start h <- c_mounts_start
@ -67,3 +74,22 @@ foreign import ccall unsafe "libmounts.h mounts_next" c_mounts_next
:: Ptr () -> IO (Ptr ()) :: Ptr () -> IO (Ptr ())
foreign import ccall unsafe "libmounts.h mounts_end" c_mounts_end foreign import ccall unsafe "libmounts.h mounts_end" c_mounts_end
:: Ptr () -> IO CInt :: Ptr () -> IO CInt
#else
{- Android does not support getmntent (well, it's a no-op stub in Bionic).
-
- But, the linux kernel's /proc/mounts is available to be parsed.
-}
getMounts :: IO [Mntent]
getMounts = catchDefaultIO [] $
mapMaybe (parse . words) . lines <$> readFile "/proc/mounts"
where
parse (device:mountpoint:fstype:_rest) = Just $ Mntent
{ mnt_fsname = device
, mnt_dir = mountpoint
, mnt_type = fstype
}
parse _ = Nothing
#endif

View file

@ -6,7 +6,7 @@
# define GETMNTINFO # define GETMNTINFO
#else #else
#if defined __ANDROID__ #if defined __ANDROID__
# warning mounts listing code not available for Android /* Android is handled by the Haskell code, not here. */
# define UNKNOWN # define UNKNOWN
#else #else
#if defined (__linux__) || defined (__FreeBSD_kernel__) #if defined (__linux__) || defined (__FreeBSD_kernel__)

View file

@ -28,8 +28,6 @@
* Ssh server and Rsync.net configuration stops where ssh * Ssh server and Rsync.net configuration stops where ssh
should be prompting for a password in the terminal. should be prompting for a password in the terminal.
* Enabling debug logging in the webapp doesn't seem to work. * Enabling debug logging in the webapp doesn't seem to work.
* S3, glacier, and local pairing are not yet enabled for Android. * glacier and local pairing are not yet enabled for Android.
* The "Files" link doesn't start a file browser. Should be possible to do * The "Files" link doesn't start a file browser. Should be possible to do
on Android via intents, I suppose? on Android via intents, I suppose?
* Does not detect mounted USB drives. getMounts is failing
probably?