📄 automount.c
字号:
} } 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 changesstatic 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 createdstatic void HandleMediaInserted(const char* device){ MountPoint* mp = sMountPointList; 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 deletedstatic 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 timesstatic 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->mountPoint) == 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); // unmounting the device is failing, so start killing processes KillProcessesWithOpenFiles(mp->mountPoint, sigkill); } } } 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 eventsint 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 ueventsint 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; 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 supportvoid 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 mountedvoid MountMedia(const char* mountPoint){ MountPoint* mp = sMountPointList; 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 unmountedvoid 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, boolean enableUms){ MountPoint* newMountPoint; LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s\n", device, mountPoint); // add a new MountPoint to the head of our linked list newMountPoint = (MountPoint *)malloc(sizeof(MountPoint)); newMountPoint->device = device; newMountPoint->mountPoint = mountPoint; newMountPoint->enableUms = enableUms; newMountPoint->umsActive = false; if (enableUms) newMountPoint->lun = sNextLun++; newMountPoint->state = kUnmounted; newMountPoint->retryCount = 0; // add to linked list newMountPoint->next = sMountPointList; sMountPointList = newMountPoint;}static void MountDevices(){ MountPoint* mp = sMountPointList; while (mp) { RequestMount(mp); mp = mp->next; }}void StartAutoMounter(){ gMassStorageConnected = ReadMassStorageState(); LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n"); MountDevices(); pthread_create(&sAutoMountThread, NULL, AutoMountThread, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -