summaryrefslogtreecommitdiffstats
path: root/mountd/AutoMount.c
diff options
context:
space:
mode:
Diffstat (limited to 'mountd/AutoMount.c')
-rw-r--r--mountd/AutoMount.c1062
1 files changed, 0 insertions, 1062 deletions
diff --git a/mountd/AutoMount.c b/mountd/AutoMount.c
deleted file mode 100644
index 12ad572..0000000
--- a/mountd/AutoMount.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-** mountd automount support
-*/
-
-#include "mountd.h"
-
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <stdlib.h>
-#include <poll.h>
-
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <linux/loop.h>
-#include <sys/inotify.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <linux/netlink.h>
-
-#define DEVPATH "/dev/block/"
-#define DEVPATHLENGTH 11 // strlen(DEVPATH)
-
-// FIXME - only one loop mount is supported at a time
-#define LOOP_DEVICE "/dev/block/loop0"
-
-// timeout value for poll() when retries are pending
-#define POLL_TIMEOUT 1000
-
-#define MAX_MOUNT_RETRIES 3
-#define MAX_UNMOUNT_RETRIES 5
-
-typedef enum {
- // device is unmounted
- kUnmounted,
-
- // attempting to mount device
- kMounting,
-
- // device is unmounted
- kMounted,
-
- // attempting to unmount device
- // so the media can be removed
- kUnmountingForEject,
-
- // attempting to mount device
- // so it can be shared via USB mass storage
- kUnmountingForUms,
-} MountState;
-
-typedef struct MountPoint {
- // block device to mount
- const char* device;
-
- // mount point for device
- const char* mountPoint;
-
- // path to the UMS driver file for specifying the block device path
- const char* driverStorePath;
-
- // true if device can be shared via
- // USB mass storage
- boolean enableUms;
-
- // Array of ASEC handles
- void *asecHandles[ASEC_STORES_MAX];
-
- // true if the device is being shared via USB mass storage
- boolean umsActive;
-
- // current state of the mount point
- MountState state;
-
- // number of mount or unmount retries so far,
- // when attempting to mount or unmount the device
- int retryCount;
-
- // next in sMountPointList linked list
- struct MountPoint* next;
-} MountPoint;
-
-// list of our mount points (does not change after initialization)
-static MountPoint* sMountPointList = NULL;
-boolean gMassStorageEnabled = false;
-boolean gMassStorageConnected = false;
-
-static pthread_t sAutoMountThread = 0;
-static pid_t gExcludedPids[2] = {-1, -1};
-
-static const char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
-
-// number of mount points that have timeouts pending
-static int sRetriesPending = 0;
-
-// for synchronization between sAutoMountThread and the server thread
-static pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
-
-// requests the USB mass_storage driver to begin or end sharing a block device
-// via USB mass storage.
-static void SetBackingStore(MountPoint* mp, boolean enable)
-{
- int fd;
-
- if (!mp->driverStorePath) {
- LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
- return;
- }
-
- LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
- fd = open(mp->driverStorePath, O_WRONLY);
- if (fd < 0)
- {
- LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
- }
- else
- {
- if (enable)
- {
- write(fd, mp->device, strlen(mp->device));
- mp->umsActive = true;
- }
- else
- {
- char ch = 0;
- write(fd, &ch, 1);
- mp->umsActive = false;
- }
- close(fd);
- }
-}
-
-static boolean ReadMassStorageState()
-{
- FILE* file = fopen("/sys/class/switch/usb_mass_storage/state", "r");
- if (file)
- {
- char buffer[20];
- fgets(buffer, sizeof(buffer), file);
- fclose(file);
- return (strncmp(buffer, "online", strlen("online")) == 0);
- }
- else
- {
- LOG_ERROR("could not read initial mass storage state\n");
- return false;
- }
-}
-
-static boolean IsLoopMounted(const char* path)
-{
- FILE* f;
- int count;
- char device[256];
- char mount_path[256];
- char rest[256];
- int result = 0;
- int path_length = strlen(path);
-
- f = fopen("/proc/mounts", "r");
- if (!f) {
- LOG_ERROR("could not open /proc/mounts\n");
- return -1;
- }
-
- do {
- count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
- if (count == 3) {
- if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0)
- {
- result = 1;
- break;
- }
- }
- } while (count == 3);
-
- fclose(f);
- LOG_MOUNT("IsLoopMounted: %s returning %d\n", path, result);
- return result;
-}
-
-static int CheckFilesystem(const char *device)
-{
- char cmdline[255];
- int rc;
-
- // XXX: SAN: Check for FAT signature
-
- int result = access(FSCK_MSDOS_PATH, X_OK);
- if (result != 0) {
- LOG_MOUNT("CheckFilesystem(%s): %s not found (skipping checks)\n", FSCK_MSDOS_PATH, device);
- return 0;
- }
-
- char *args[7];
- args[0] = FSCK_MSDOS_PATH;
- args[1] = "-v";
- args[2] = "-V";
- args[3] = "-w";
- args[4] = "-p";
- args[5] = device;
- args[6] = NULL;
-
- LOG_MOUNT("Checking filesystem on %s\n", device);
- rc = logwrap(6, args);
-
- // XXX: We need to be able to distinguish between a FS with an error
- // and a block device which does not have a FAT fs at all on it
- if (rc == 0) {
- LOG_MOUNT("Filesystem check completed OK\n");
- return 0;
- } else if (rc == 1) {
- LOG_MOUNT("Filesystem check failed (general failure)\n");
- return -EINVAL;
- } else if (rc == 2) {
- LOG_MOUNT("Filesystem check failed (invalid usage)\n");
- return -EIO;
- } else {
- LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
- return -EIO;
- }
-}
-
-static int DoMountDevice(const char* device, const char* mountPoint)
-{
- LOG_MOUNT("Attempting mount of %s on %s\n", device, mountPoint);
-
-#if CREATE_MOUNT_POINTS
- // make sure mount point exists
- mkdir(mountPoint, 0000);
-#endif
-
- int flags = 0;
-
- if (device && strncmp(device, "/dev/", 5))
- {
- // mount with the loop driver if device does not start with "/dev/"
- int file_fd, device_fd;
-
- // FIXME - only one loop mount supported at a time
- file_fd = open(device, O_RDWR);
- if (file_fd < -1) {
- LOG_ERROR("open backing file %s failed\n", device);
- return 1;
- }
- device_fd = open(LOOP_DEVICE, O_RDWR);
- if (device_fd < -1) {
- LOG_ERROR("open %s failed", LOOP_DEVICE);
- close(file_fd);
- return 1;
- }
- if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0)
- {
- LOG_ERROR("ioctl LOOP_SET_FD failed\n");
- close(file_fd);
- close(device_fd);
- return 1;
- }
-
- close(file_fd);
- close(device_fd);
- device = "/dev/block/loop0";
- }
-
- int result = access(device, R_OK);
- if (result) {
- LOG_ERROR("Unable to access '%s' (%d)\n", device, errno);
- return -errno;
- }
-
-#if 0
- if ((result = CheckFilesystem(device))) {
- LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
- // XXX: Notify framework - need a new SDCARD state for the following:
- // - SD cards which are not present
- // - SD cards with no partition table
- // - SD cards with no filesystem
- // - SD cards with bad filesystem
- return result;
- }
-#endif
-
- // Extra safety measures:
- flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
- // Also, set fmask = 711 so that files cannot be marked executable,
- // and cannot by opened by uid 1000 (system). Similar, dmask = 700
- // so that directories cannot be accessed by uid 1000.
- result = mount(device, mountPoint, "vfat", flags,
- "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
- if (result && errno == EROFS) {
- LOG_ERROR("mount failed EROFS, try again read-only\n");
- flags |= MS_RDONLY;
- result = mount(device, mountPoint, "vfat", flags,
- "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
- }
-
- if (result == 0) {
- LOG_MOUNT("Partition %s mounted on %s\n", device, mountPoint);
- NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
-
- MountPoint* mp = sMountPointList;
- while (mp) {
- if (!strcmp(mountPoint, mp->mountPoint)) {
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (mp->asecHandles[i] != NULL) {
- int a_result;
- if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
- LOG_ERROR("ASEC start failure (%d)\n", a_result);
- }
- }
- }
- break;
- }
- mp = mp -> next;
- }
- } else if (errno == EBUSY) {
- LOG_MOUNT("Mount failed (already mounted)\n");
- result = 0;
- } else {
-#if CREATE_MOUNT_POINTS
- rmdir(mountPoint);
-#endif
- LOG_MOUNT("Unable to mount %s on %s\n", device, mountPoint);
- }
-
- return result;
-}
-
-static int DoUnmountDevice(MountPoint *mp)
-{
- boolean loop = IsLoopMounted(mp->mountPoint);
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
- AsecStop(mp->asecHandles[i]);
- }
-
- int result = umount(mp->mountPoint);
- LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
-
- if (result == 0)
- {
-#if CREATE_MOUNT_POINTS
- rmdir(mountPoint);
-#endif
- NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
- }
-
- if (loop)
- {
- // free the loop device
- int loop_fd = open(LOOP_DEVICE, O_RDONLY);
- if (loop_fd < -1) {
- LOG_ERROR("open loop device failed\n");
- }
- if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
- LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
- }
-
- close(loop_fd);
- }
-
- // ignore EINVAL and ENOENT, since it usually means the device is already unmounted
- if (result && (errno == EINVAL || errno == ENOENT))
- result = 0;
-
- return result;
-}
-
-static int MountPartition(const char* device, const char* mountPoint)
-{
- char buf[100];
- int i;
-
- // attempt to mount subpartitions of the device
- for (i = 1; i < 10; i++)
- {
- int rc;
- snprintf(buf, sizeof(buf), "%sp%d", device, i);
- rc = DoMountDevice(buf, mountPoint);
- LOG_MOUNT("DoMountDevice(%s, %s) = %d\n", buf, mountPoint, rc);
- if (rc == 0)
- return 0;
- }
-
- return -1;
-}
-
-/*****************************************************
- *
- * AUTO-MOUNTER STATE ENGINE IMPLEMENTATION
- *
- *****************************************************/
-
-static void SetState(MountPoint* mp, MountState state)
-{
- mp->state = state;
-}
-
-// Enter a state that requires retries and timeouts.
-static void SetRetries(MountPoint* mp, MountState state)
-{
- SetState(mp, state);
- mp->retryCount = 0;
-
- sRetriesPending++;
- // wake up the automounter thread if we are being called
- // from somewhere else with no retries pending
- if (sRetriesPending == 1 && sAutoMountThread != 0 &&
- pthread_self() != sAutoMountThread)
- pthread_kill(sAutoMountThread, SIGUSR1);
-}
-
-// Exit a state that requires retries and timeouts.
-static void ClearRetries(MountPoint* mp, MountState state)
-{
- SetState(mp, state);
- sRetriesPending--;
-}
-
-// attempt to mount the specified mount point.
-// set up retry/timeout if it does not succeed at first.
-static void RequestMount(MountPoint* mp)
-{
- LOG_MOUNT("RequestMount %s\n", mp->mountPoint);
-
- if (mp->state != kMounted && mp->state != kMounting &&
- access(mp->device, R_OK) == 0) {
- // try raw device first
- if (DoMountDevice(mp->device, mp->mountPoint) == 0 ||
- MountPartition(mp->device, mp->mountPoint) == 0)
- {
- SetState(mp, kMounted);
- }
- else
- {
- SetState(mp, kMounting);
- mp->retryCount = 0;
- SetRetries(mp, kMounting);
- }
- }
-}
-
-// Force the kernel to drop all caches.
-static void DropSystemCaches(void)
-{
- int fd;
-
- LOG_MOUNT("Dropping system caches\n");
- fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
-
- if (fd > 0) {
- char ch = 3;
- int rc;
-
- rc = write(fd, &ch, 1);
- if (rc <= 0)
- LOG_MOUNT("Error dropping caches (%d)\n", rc);
- close(fd);
- }
-}
-
-// attempt to unmount the specified mount point.
-// set up retry/timeout if it does not succeed at first.
-static void RequestUnmount(MountPoint* mp, MountState retryState)
-{
- int result;
-
- LOG_MOUNT("RequestUnmount %s retryState: %d\n", mp->mountPoint, retryState);
-
- if (mp->state == kMounted)
- {
- SendUnmountRequest(mp->mountPoint);
-
- // do this in case the user pulls the SD card before we can successfully unmount
- sync();
- DropSystemCaches();
-
- if (DoUnmountDevice(mp) == 0)
- {
- SetState(mp, kUnmounted);
- if (retryState == kUnmountingForUms)
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- }
- else
- {
- LOG_MOUNT("unmount failed, set retry\n");
- SetRetries(mp, retryState);
- }
- }
- else if (mp->state == kMounting)
- {
- SetState(mp, kUnmounted);
- }
-}
-
-// returns true if the mount point should be shared via USB mass storage
-static boolean MassStorageEnabledForMountPoint(const MountPoint* mp)
-{
- return (gMassStorageEnabled && gMassStorageConnected && mp->enableUms);
-}
-
-// handles changes in gMassStorageEnabled and gMassStorageConnected
-static void MassStorageStateChanged()
-{
- MountPoint* mp = sMountPointList;
-
- boolean enable = (gMassStorageEnabled && gMassStorageConnected);
- LOG_MOUNT("MassStorageStateChanged enable: %s\n", (enable ? "true" : "false"));
-
- while (mp)
- {
- if (mp->enableUms)
- {
- if (enable)
- {
- if (mp->state == kMounting)
- SetState(mp, kUnmounted);
- if (mp->state == kUnmounted)
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- else
- {
- LOG_MOUNT("MassStorageStateChanged requesting unmount\n");
- // need to successfully unmount first
- RequestUnmount(mp, kUnmountingForUms);
- }
- } else if (mp->umsActive) {
- SetBackingStore(mp, false);
- if (mp->state == kUnmountingForUms)
- {
- ClearRetries(mp, kMounted);
- NotifyMediaState(mp->mountPoint, MEDIA_MOUNTED, false);
- }
- else if (mp->state == kUnmounted)
- {
- NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
- RequestMount(mp);
- }
- }
- }
-
- mp = mp->next;
- }
-}
-
-// called when USB mass storage connected state changes
-static void HandleMassStorageOnline(boolean connected)
-{
- if (connected != gMassStorageConnected)
- {
- gMassStorageConnected = connected;
- SendMassStorageConnected(connected);
-
- // we automatically reset to mass storage off after USB is connected
- if (!connected)
- gMassStorageEnabled = false;
-
- MassStorageStateChanged();
- }
-}
-
-// called when a new block device has been created
-static void HandleMediaInserted(const char* device)
-{
- MountPoint* mp = sMountPointList;
-
- LOG_MOUNT("HandleMediaInserted(%s):\n", device);
-
- while (mp)
- {
- // see if the device matches mount point's block device
- if (mp->state == kUnmounted &&
- strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
- {
- if (MassStorageEnabledForMountPoint(mp))
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- else
- RequestMount(mp);
- }
- mp = mp->next;
- }
-}
-
-// called when a new block device has been deleted
-static void HandleMediaRemoved(const char* device)
-{
- MountPoint* mp = sMountPointList;
- while (mp)
- {
- if (strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
- {
- if (mp->enableUms)
- SetBackingStore(mp, false);
-
- if (mp->state == kMounted)
- {
- RequestUnmount(mp, kUnmountingForEject);
- NotifyMediaState(mp->mountPoint, MEDIA_BAD_REMOVAL, false);
- }
-
- NotifyMediaState(mp->mountPoint, MEDIA_REMOVED, false);
- break;
- }
- mp = mp->next;
- }
-}
-
-// Handle retrying to mount or unmount devices,
-// and handle timeout condition if we have tried too many times
-static void HandleRetries()
-{
- MountPoint* mp = sMountPointList;
-
- while (mp)
- {
- if (mp->state == kMounting)
- {
- if (MountPartition(mp->device, mp->mountPoint) == 0)
- {
- // mount succeeded - clear the retry for this mount point
- ClearRetries(mp, kMounted);
- }
- else
- {
- mp->retryCount++;
- if (mp->retryCount == MAX_MOUNT_RETRIES)
- {
- // we failed to mount the device too many times
- ClearRetries(mp, kUnmounted);
- // notify that we failed to mount
- NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTABLE, false);
- }
- }
- }
- else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
- {
- if (DoUnmountDevice(mp) == 0)
- {
- // unmounting succeeded
- // start mass storage, if state is kUnmountingForUms
- if (mp->state == kUnmountingForUms)
- {
- SetBackingStore(mp, true);
- NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
- }
- // clear the retry for this mount point
- ClearRetries(mp, kUnmounted);
- }
- else
- {
- mp->retryCount++;
- if (mp->retryCount >= MAX_UNMOUNT_RETRIES)
- {
- // kill any processes that are preventing the device from unmounting
- // send SIGKILL instead of SIGTERM if the first attempt did not succeed
- boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
-
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
- LOG_MOUNT("Killing processes for ASEC path '%s'\n",
- AsecMountPoint(mp->asecHandles[i]));
- KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
- sigkill,
- gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
-
- // Now that we've killed the processes, try to stop the volume again
- AsecStop(mp->asecHandles[i]);
- }
- }
-
- // unmounting the device is failing, so start killing processes
- KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids,
- sizeof(gExcludedPids) / sizeof(pid_t));
-
- }
- }
- }
-
- mp = mp->next;
- }
-}
-
-/*****************************************************
- *
- * AUTO-MOUNTER THREAD
- *
- *****************************************************/
-
-static void sigusr1_handler(int signo)
-{
- // don't need to do anything here
-}
-
-// create a socket for listening to inotify events
-int CreateINotifySocket()
-{
- // initialize inotify
- int fd = inotify_init();
-
- if (fd < 0) {
- LOG_ERROR("inotify_init failed, %s\n", strerror(errno));
- return -1;
- }
-
- fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
-
- return fd;
-}
-
-
-// create a socket for listening to uevents
-int CreateUEventSocket()
-{
- struct sockaddr_nl addr;
- int sz = 64*1024;
- int fd;
-
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
- addr.nl_pid = getpid();
- addr.nl_groups = 0xffffffff;
-
- fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- if(fd < 0)
- {
- LOG_ERROR("could not create NETLINK_KOBJECT_UEVENT socket\n");
- return -1;
- }
-
- setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
-
- if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOG_ERROR("could not bind NETLINK_KOBJECT_UEVENT socket\n");
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-/*
- * Automounter main event thread.
- * This thread listens for block devices being created and deleted via inotify,
- * and listens for changes in the USB mass storage connected/disconnected via uevents from the
- * power supply driver.
- * This thread also handles retries and timeouts for requests to mount or unmount a device.
- */
-static void* AutoMountThread(void* arg)
-{
- int inotify_fd;
- int uevent_fd;
- int id;
- struct sigaction actions;
-
- gExcludedPids[1] = getpid();
-
- memset(&actions, 0, sizeof(actions));
- sigemptyset(&actions.sa_mask);
- actions.sa_flags = 0;
- actions.sa_handler = sigusr1_handler;
- sigaction(SIGUSR1, &actions, NULL);
-
- // initialize inotify
- inotify_fd = CreateINotifySocket();
- // watch for files created and deleted in "/dev"
- inotify_add_watch(inotify_fd, DEVPATH, IN_CREATE|IN_DELETE);
-
- // initialize uevent watcher
- uevent_fd = CreateUEventSocket();
- if (uevent_fd < 0)
- {
- LOG_ERROR("CreateUEventSocket failed, %s\n", strerror(errno));
- return NULL;
- }
-
- while (1)
- {
- struct pollfd fds[2];
- int timeout, result;
-
-#define INOTIFY_IDX 0
-#define UEVENT_IDX 1
-
- fds[INOTIFY_IDX].fd = inotify_fd;
- fds[INOTIFY_IDX].events = POLLIN;
- fds[INOTIFY_IDX].revents = 0;
- fds[UEVENT_IDX].fd = uevent_fd;
- fds[UEVENT_IDX].events = POLLIN;
- fds[UEVENT_IDX].revents = 0;
-
- // wait for an event or a timeout to occur.
- // poll() can also return in response to a SIGUSR1 signal
- timeout = (sRetriesPending ? POLL_TIMEOUT : -1);
- result = poll(fds, 2, timeout);
-
- // lock the mutex while we are handling events
- pthread_mutex_lock(&sMutex);
-
- // handle inotify notifications for block device creation and deletion
- if (fds[INOTIFY_IDX].revents == POLLIN)
- {
- struct inotify_event event;
- char buffer[512];
- int length = read(inotify_fd, buffer, sizeof(buffer));
- int offset = 0;
-
- while (length >= (int)sizeof(struct inotify_event))
- {
- struct inotify_event* event = (struct inotify_event *)&buffer[offset];
-
- if (event->mask == IN_CREATE)
- {
- LOG_MOUNT("/dev/block/%s created\n", event->name);
- HandleMediaInserted(event->name);
- }
- else if (event->mask == IN_DELETE)
- {
- LOG_MOUNT("/dev/block/%s deleted\n", event->name);
- HandleMediaRemoved(event->name);
- }
-
- int size = sizeof(struct inotify_event) + event->len;
- length -= size;
- offset += size;
- }
- }
-
- // handle uevent notifications for USB state changes
- if (fds[UEVENT_IDX].revents == POLLIN)
- {
- char buffer[64*1024];
- int count;
-
- count = recv(uevent_fd, buffer, sizeof(buffer), 0);
- if (count > 0) {
- char* s = buffer;
- char* end = s + count;
- char* type = NULL;
- char* online = NULL;
- char* switchName = NULL;
- char* switchState = NULL;
-
- while (s < end) {
- if (!strncmp("POWER_SUPPLY_TYPE=", s, strlen("POWER_SUPPLY_TYPE=")))
- type = s + strlen("POWER_SUPPLY_TYPE=");
- else if (!strncmp("POWER_SUPPLY_ONLINE=", s, strlen("POWER_SUPPLY_ONLINE=")))
- online = s + strlen("POWER_SUPPLY_ONLINE=");
- else if (!strncmp("SWITCH_NAME=", s, strlen("SWITCH_NAME=")))
- switchName = s + strlen("SWITCH_NAME=");
- else if (!strncmp("SWITCH_STATE=", s, strlen("SWITCH_STATE=")))
- switchState = s + strlen("SWITCH_STATE=");
- s += (strlen(s) + 1);
- }
-
- // we use the usb_mass_storage switch state to tell us when USB is online
- if (switchName && switchState &&
- !strcmp(switchName, "usb_mass_storage") && !strcmp(switchState, "online"))
- {
- LOG_MOUNT("USB online\n");
- HandleMassStorageOnline(true);
- }
-
- // and we use the power supply state to tell us when USB is offline
- // we can't rely on the switch for offline detection because we get false positives
- // when USB is reenumerated by the host.
- if (type && online && !strcmp(type, "USB") && !strcmp(online, "0"))
- {
- LOG_MOUNT("USB offline\n");
- HandleMassStorageOnline(false);
- }
- }
- }
-
- // handle retries
- if (sRetriesPending)
- HandleRetries();
-
- // done handling events, so unlock the mutex
- pthread_mutex_unlock(&sMutex);
- }
-
- inotify_rm_watch(inotify_fd, id);
- close(inotify_fd);
- close(uevent_fd);
-
- return NULL;
-}
-
-/*****************************************************
- *
- * THESE FUNCTIONS ARE CALLED FROM THE SERVER THREAD
- *
- *****************************************************/
-
-// Called to enable or disable USB mass storage support
-void EnableMassStorage(boolean enable)
-{
- pthread_mutex_lock(&sMutex);
-
- LOG_MOUNT("EnableMassStorage %s\n", (enable ? "true" : "false"));
- gMassStorageEnabled = enable;
- MassStorageStateChanged();
- pthread_mutex_unlock(&sMutex);
- }
-
-// Called to request that the specified mount point be mounted
-void MountMedia(const char* mountPoint)
-{
- MountPoint* mp = sMountPointList;
-
- LOG_MOUNT("MountMedia(%s)\n", mountPoint);
-
- pthread_mutex_lock(&sMutex);
- while (mp)
- {
- if (strcmp(mp->mountPoint, mountPoint) == 0)
- {
- if (mp->state == kUnmountingForEject)
- {
- // handle the case where we try to remount before we actually unmounted
- ClearRetries(mp, kMounted);
- }
-
- // don't attempt to mount if mass storage is active
- if (!MassStorageEnabledForMountPoint(mp))
- RequestMount(mp);
- }
-
- mp = mp->next;
- }
- pthread_mutex_unlock(&sMutex);
- }
-
-// Called to request that the specified mount point be unmounted
-void UnmountMedia(const char* mountPoint)
-{
- MountPoint* mp = sMountPointList;
-
- pthread_mutex_lock(&sMutex);
- while (mp)
- {
- if (strcmp(mp->mountPoint, mountPoint) == 0)
- RequestUnmount(mp, kUnmountingForEject);
-
- mp = mp->next;
- }
- pthread_mutex_unlock(&sMutex);
-}
-
-boolean IsMassStorageEnabled()
-{
- return gMassStorageEnabled;
-}
-
-boolean IsMassStorageConnected()
-{
- return gMassStorageConnected;
-}
-
-/***********************************************
- *
- * THESE FUNCTIONS ARE CALLED ONLY AT STARTUP
- *
- ***********************************************/
-
-void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
-{
- MountPoint* newMountPoint;
-
- LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
- // add a new MountPoint to the head of our linked list
- newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
- newMountPoint->device = device;
- newMountPoint->mountPoint = mountPoint;
- newMountPoint->driverStorePath = driverStorePath;
- newMountPoint->enableUms = enableUms;
- newMountPoint->umsActive = false;
- newMountPoint->state = kUnmounted;
- newMountPoint->retryCount = 0;
-
- // add to linked list
- newMountPoint->next = sMountPointList;
- sMountPointList = newMountPoint;
- return newMountPoint;
-}
-
-int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
- const char *mount_point, const char *crypt)
-{
- MountPoint *mp = (MountPoint *) Mp;
- int i;
-
- for (i = 0; i < ASEC_STORES_MAX; i++) {
- if (!mp->asecHandles[i])
- break;
- }
-
- if (i == ASEC_STORES_MAX) {
- LOG_ERROR("Maximum # of ASEC stores exceeded\n");
- return -EINVAL;
- }
-
- if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
- return -1;
-
- return 0;
-}
-static void MountDevices()
-{
- MountPoint* mp = sMountPointList;
- while (mp)
- {
- RequestMount(mp);
- mp = mp->next;
- }
-}
-
-void StartAutoMounter()
-{
- gExcludedPids[0] = getpid();
-
- gMassStorageConnected = ReadMassStorageState();
- LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
-
- MountDevices();
- pthread_create(&sAutoMountThread, NULL, AutoMountThread, NULL);
-}