diff options
Diffstat (limited to 'mountd/AutoMount.c')
-rw-r--r-- | mountd/AutoMount.c | 1062 |
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); -} |