blob: 12ad572e9222eb315326eac6448e4df391b838fb [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18** mountd automount support
19*/
20
21#include "mountd.h"
22
23#include <pthread.h>
24#include <stdio.h>
25#include <unistd.h>
26#include <string.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <ctype.h>
30#include <pwd.h>
31#include <stdlib.h>
32#include <poll.h>
33
34#include <sys/mount.h>
35#include <sys/stat.h>
36#include <linux/loop.h>
37#include <sys/inotify.h>
38#include <sys/socket.h>
39#include <sys/un.h>
40#include <linux/netlink.h>
41
42#define DEVPATH "/dev/block/"
43#define DEVPATHLENGTH 11 // strlen(DEVPATH)
44
45// FIXME - only one loop mount is supported at a time
46#define LOOP_DEVICE "/dev/block/loop0"
47
48// timeout value for poll() when retries are pending
49#define POLL_TIMEOUT 1000
50
51#define MAX_MOUNT_RETRIES 3
52#define MAX_UNMOUNT_RETRIES 5
53
54typedef enum {
55 // device is unmounted
56 kUnmounted,
57
58 // attempting to mount device
59 kMounting,
60
61 // device is unmounted
62 kMounted,
63
64 // attempting to unmount device
65 // so the media can be removed
66 kUnmountingForEject,
67
68 // attempting to mount device
69 // so it can be shared via USB mass storage
70 kUnmountingForUms,
71} MountState;
72
73typedef struct MountPoint {
74 // block device to mount
75 const char* device;
76
77 // mount point for device
78 const char* mountPoint;
79
80 // path to the UMS driver file for specifying the block device path
81 const char* driverStorePath;
82
83 // true if device can be shared via
84 // USB mass storage
85 boolean enableUms;
86
87 // Array of ASEC handles
88 void *asecHandles[ASEC_STORES_MAX];
89
90 // true if the device is being shared via USB mass storage
91 boolean umsActive;
92
93 // current state of the mount point
94 MountState state;
95
96 // number of mount or unmount retries so far,
97 // when attempting to mount or unmount the device
98 int retryCount;
99
100 // next in sMountPointList linked list
101 struct MountPoint* next;
102} MountPoint;
103
104// list of our mount points (does not change after initialization)
105static MountPoint* sMountPointList = NULL;
106boolean gMassStorageEnabled = false;
107boolean gMassStorageConnected = false;
108
109static pthread_t sAutoMountThread = 0;
110static pid_t gExcludedPids[2] = {-1, -1};
111
112static const char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
113
114// number of mount points that have timeouts pending
115static int sRetriesPending = 0;
116
117// for synchronization between sAutoMountThread and the server thread
118static pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
119
120// requests the USB mass_storage driver to begin or end sharing a block device
121// via USB mass storage.
122static void SetBackingStore(MountPoint* mp, boolean enable)
123{
124 int fd;
125
126 if (!mp->driverStorePath) {
127 LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
128 return;
129 }
130
131 LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
132 fd = open(mp->driverStorePath, O_WRONLY);
133 if (fd < 0)
134 {
135 LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
136 }
137 else
138 {
139 if (enable)
140 {
141 write(fd, mp->device, strlen(mp->device));
142 mp->umsActive = true;
143 }
144 else
145 {
146 char ch = 0;
147 write(fd, &ch, 1);
148 mp->umsActive = false;
149 }
150 close(fd);
151 }
152}
153
154static boolean ReadMassStorageState()
155{
156 FILE* file = fopen("/sys/class/switch/usb_mass_storage/state", "r");
157 if (file)
158 {
159 char buffer[20];
160 fgets(buffer, sizeof(buffer), file);
161 fclose(file);
162 return (strncmp(buffer, "online", strlen("online")) == 0);
163 }
164 else
165 {
166 LOG_ERROR("could not read initial mass storage state\n");
167 return false;
168 }
169}
170
171static boolean IsLoopMounted(const char* path)
172{
173 FILE* f;
174 int count;
175 char device[256];
176 char mount_path[256];
177 char rest[256];
178 int result = 0;
179 int path_length = strlen(path);
180
181 f = fopen("/proc/mounts", "r");
182 if (!f) {
183 LOG_ERROR("could not open /proc/mounts\n");
184 return -1;
185 }
186
187 do {
188 count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
189 if (count == 3) {
190 if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0)
191 {
192 result = 1;
193 break;
194 }
195 }
196 } while (count == 3);
197
198 fclose(f);
199 LOG_MOUNT("IsLoopMounted: %s returning %d\n", path, result);
200 return result;
201}
202
203static int CheckFilesystem(const char *device)
204{
205 char cmdline[255];
206 int rc;
207
208 // XXX: SAN: Check for FAT signature
209
210 int result = access(FSCK_MSDOS_PATH, X_OK);
211 if (result != 0) {
212 LOG_MOUNT("CheckFilesystem(%s): %s not found (skipping checks)\n", FSCK_MSDOS_PATH, device);
213 return 0;
214 }
215
216 char *args[7];
217 args[0] = FSCK_MSDOS_PATH;
218 args[1] = "-v";
219 args[2] = "-V";
220 args[3] = "-w";
221 args[4] = "-p";
222 args[5] = device;
223 args[6] = NULL;
224
225 LOG_MOUNT("Checking filesystem on %s\n", device);
226 rc = logwrap(6, args);
227
228 // XXX: We need to be able to distinguish between a FS with an error
229 // and a block device which does not have a FAT fs at all on it
230 if (rc == 0) {
231 LOG_MOUNT("Filesystem check completed OK\n");
232 return 0;
233 } else if (rc == 1) {
234 LOG_MOUNT("Filesystem check failed (general failure)\n");
235 return -EINVAL;
236 } else if (rc == 2) {
237 LOG_MOUNT("Filesystem check failed (invalid usage)\n");
238 return -EIO;
239 } else {
240 LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
241 return -EIO;
242 }
243}
244
245static int DoMountDevice(const char* device, const char* mountPoint)
246{
247 LOG_MOUNT("Attempting mount of %s on %s\n", device, mountPoint);
248
249#if CREATE_MOUNT_POINTS
250 // make sure mount point exists
251 mkdir(mountPoint, 0000);
252#endif
253
254 int flags = 0;
255
256 if (device && strncmp(device, "/dev/", 5))
257 {
258 // mount with the loop driver if device does not start with "/dev/"
259 int file_fd, device_fd;
260
261 // FIXME - only one loop mount supported at a time
262 file_fd = open(device, O_RDWR);
263 if (file_fd < -1) {
264 LOG_ERROR("open backing file %s failed\n", device);
265 return 1;
266 }
267 device_fd = open(LOOP_DEVICE, O_RDWR);
268 if (device_fd < -1) {
269 LOG_ERROR("open %s failed", LOOP_DEVICE);
270 close(file_fd);
271 return 1;
272 }
273 if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0)
274 {
275 LOG_ERROR("ioctl LOOP_SET_FD failed\n");
276 close(file_fd);
277 close(device_fd);
278 return 1;
279 }
280
281 close(file_fd);
282 close(device_fd);
283 device = "/dev/block/loop0";
284 }
285
286 int result = access(device, R_OK);
287 if (result) {
288 LOG_ERROR("Unable to access '%s' (%d)\n", device, errno);
289 return -errno;
290 }
291
292#if 0
293 if ((result = CheckFilesystem(device))) {
294 LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
295 // XXX: Notify framework - need a new SDCARD state for the following:
296 // - SD cards which are not present
297 // - SD cards with no partition table
298 // - SD cards with no filesystem
299 // - SD cards with bad filesystem
300 return result;
301 }
302#endif
303
304 // Extra safety measures:
305 flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
306 // Also, set fmask = 711 so that files cannot be marked executable,
307 // and cannot by opened by uid 1000 (system). Similar, dmask = 700
308 // so that directories cannot be accessed by uid 1000.
309 result = mount(device, mountPoint, "vfat", flags,
310 "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
311 if (result && errno == EROFS) {
312 LOG_ERROR("mount failed EROFS, try again read-only\n");
313 flags |= MS_RDONLY;
314 result = mount(device, mountPoint, "vfat", flags,
315 "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
316 }
317
318 if (result == 0) {
319 LOG_MOUNT("Partition %s mounted on %s\n", device, mountPoint);
320 NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
321
322 MountPoint* mp = sMountPointList;
323 while (mp) {
324 if (!strcmp(mountPoint, mp->mountPoint)) {
325 int i;
326
327 for (i = 0; i < ASEC_STORES_MAX; i++) {
328 if (mp->asecHandles[i] != NULL) {
329 int a_result;
330 if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
331 LOG_ERROR("ASEC start failure (%d)\n", a_result);
332 }
333 }
334 }
335 break;
336 }
337 mp = mp -> next;
338 }
339 } else if (errno == EBUSY) {
340 LOG_MOUNT("Mount failed (already mounted)\n");
341 result = 0;
342 } else {
343#if CREATE_MOUNT_POINTS
344 rmdir(mountPoint);
345#endif
346 LOG_MOUNT("Unable to mount %s on %s\n", device, mountPoint);
347 }
348
349 return result;
350}
351
352static int DoUnmountDevice(MountPoint *mp)
353{
354 boolean loop = IsLoopMounted(mp->mountPoint);
355 int i;
356
357 for (i = 0; i < ASEC_STORES_MAX; i++) {
358 if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
359 AsecStop(mp->asecHandles[i]);
360 }
361
362 int result = umount(mp->mountPoint);
363 LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
364
365 if (result == 0)
366 {
367#if CREATE_MOUNT_POINTS
368 rmdir(mountPoint);
369#endif
370 NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
371 }
372
373 if (loop)
374 {
375 // free the loop device
376 int loop_fd = open(LOOP_DEVICE, O_RDONLY);
377 if (loop_fd < -1) {
378 LOG_ERROR("open loop device failed\n");
379 }
380 if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
381 LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
382 }
383
384 close(loop_fd);
385 }
386
387 // ignore EINVAL and ENOENT, since it usually means the device is already unmounted
388 if (result && (errno == EINVAL || errno == ENOENT))
389 result = 0;
390
391 return result;
392}
393
394static int MountPartition(const char* device, const char* mountPoint)
395{
396 char buf[100];
397 int i;
398
399 // attempt to mount subpartitions of the device
400 for (i = 1; i < 10; i++)
401 {
402 int rc;
403 snprintf(buf, sizeof(buf), "%sp%d", device, i);
404 rc = DoMountDevice(buf, mountPoint);
405 LOG_MOUNT("DoMountDevice(%s, %s) = %d\n", buf, mountPoint, rc);
406 if (rc == 0)
407 return 0;
408 }
409
410 return -1;
411}
412
413/*****************************************************
414 *
415 * AUTO-MOUNTER STATE ENGINE IMPLEMENTATION
416 *
417 *****************************************************/
418
419static void SetState(MountPoint* mp, MountState state)
420{
421 mp->state = state;
422}
423
424// Enter a state that requires retries and timeouts.
425static void SetRetries(MountPoint* mp, MountState state)
426{
427 SetState(mp, state);
428 mp->retryCount = 0;
429
430 sRetriesPending++;
431 // wake up the automounter thread if we are being called
432 // from somewhere else with no retries pending
433 if (sRetriesPending == 1 && sAutoMountThread != 0 &&
434 pthread_self() != sAutoMountThread)
435 pthread_kill(sAutoMountThread, SIGUSR1);
436}
437
438// Exit a state that requires retries and timeouts.
439static void ClearRetries(MountPoint* mp, MountState state)
440{
441 SetState(mp, state);
442 sRetriesPending--;
443}
444
445// attempt to mount the specified mount point.
446// set up retry/timeout if it does not succeed at first.
447static void RequestMount(MountPoint* mp)
448{
449 LOG_MOUNT("RequestMount %s\n", mp->mountPoint);
450
451 if (mp->state != kMounted && mp->state != kMounting &&
452 access(mp->device, R_OK) == 0) {
453 // try raw device first
454 if (DoMountDevice(mp->device, mp->mountPoint) == 0 ||
455 MountPartition(mp->device, mp->mountPoint) == 0)
456 {
457 SetState(mp, kMounted);
458 }
459 else
460 {
461 SetState(mp, kMounting);
462 mp->retryCount = 0;
463 SetRetries(mp, kMounting);
464 }
465 }
466}
467
468// Force the kernel to drop all caches.
469static void DropSystemCaches(void)
470{
471 int fd;
472
473 LOG_MOUNT("Dropping system caches\n");
474 fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
475
476 if (fd > 0) {
477 char ch = 3;
478 int rc;
479
480 rc = write(fd, &ch, 1);
481 if (rc <= 0)
482 LOG_MOUNT("Error dropping caches (%d)\n", rc);
483 close(fd);
484 }
485}
486
487// attempt to unmount the specified mount point.
488// set up retry/timeout if it does not succeed at first.
489static void RequestUnmount(MountPoint* mp, MountState retryState)
490{
491 int result;
492
493 LOG_MOUNT("RequestUnmount %s retryState: %d\n", mp->mountPoint, retryState);
494
495 if (mp->state == kMounted)
496 {
497 SendUnmountRequest(mp->mountPoint);
498
499 // do this in case the user pulls the SD card before we can successfully unmount
500 sync();
501 DropSystemCaches();
502
503 if (DoUnmountDevice(mp) == 0)
504 {
505 SetState(mp, kUnmounted);
506 if (retryState == kUnmountingForUms)
507 {
508 SetBackingStore(mp, true);
509 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
510 }
511 }
512 else
513 {
514 LOG_MOUNT("unmount failed, set retry\n");
515 SetRetries(mp, retryState);
516 }
517 }
518 else if (mp->state == kMounting)
519 {
520 SetState(mp, kUnmounted);
521 }
522}
523
524// returns true if the mount point should be shared via USB mass storage
525static boolean MassStorageEnabledForMountPoint(const MountPoint* mp)
526{
527 return (gMassStorageEnabled && gMassStorageConnected && mp->enableUms);
528}
529
530// handles changes in gMassStorageEnabled and gMassStorageConnected
531static void MassStorageStateChanged()
532{
533 MountPoint* mp = sMountPointList;
534
535 boolean enable = (gMassStorageEnabled && gMassStorageConnected);
536 LOG_MOUNT("MassStorageStateChanged enable: %s\n", (enable ? "true" : "false"));
537
538 while (mp)
539 {
540 if (mp->enableUms)
541 {
542 if (enable)
543 {
544 if (mp->state == kMounting)
545 SetState(mp, kUnmounted);
546 if (mp->state == kUnmounted)
547 {
548 SetBackingStore(mp, true);
549 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
550 }
551 else
552 {
553 LOG_MOUNT("MassStorageStateChanged requesting unmount\n");
554 // need to successfully unmount first
555 RequestUnmount(mp, kUnmountingForUms);
556 }
557 } else if (mp->umsActive) {
558 SetBackingStore(mp, false);
559 if (mp->state == kUnmountingForUms)
560 {
561 ClearRetries(mp, kMounted);
562 NotifyMediaState(mp->mountPoint, MEDIA_MOUNTED, false);
563 }
564 else if (mp->state == kUnmounted)
565 {
566 NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
567 RequestMount(mp);
568 }
569 }
570 }
571
572 mp = mp->next;
573 }
574}
575
576// called when USB mass storage connected state changes
577static void HandleMassStorageOnline(boolean connected)
578{
579 if (connected != gMassStorageConnected)
580 {
581 gMassStorageConnected = connected;
582 SendMassStorageConnected(connected);
583
584 // we automatically reset to mass storage off after USB is connected
585 if (!connected)
586 gMassStorageEnabled = false;
587
588 MassStorageStateChanged();
589 }
590}
591
592// called when a new block device has been created
593static void HandleMediaInserted(const char* device)
594{
595 MountPoint* mp = sMountPointList;
596
597 LOG_MOUNT("HandleMediaInserted(%s):\n", device);
598
599 while (mp)
600 {
601 // see if the device matches mount point's block device
602 if (mp->state == kUnmounted &&
603 strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
604 {
605 if (MassStorageEnabledForMountPoint(mp))
606 {
607 SetBackingStore(mp, true);
608 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
609 }
610 else
611 RequestMount(mp);
612 }
613 mp = mp->next;
614 }
615}
616
617// called when a new block device has been deleted
618static void HandleMediaRemoved(const char* device)
619{
620 MountPoint* mp = sMountPointList;
621 while (mp)
622 {
623 if (strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
624 {
625 if (mp->enableUms)
626 SetBackingStore(mp, false);
627
628 if (mp->state == kMounted)
629 {
630 RequestUnmount(mp, kUnmountingForEject);
631 NotifyMediaState(mp->mountPoint, MEDIA_BAD_REMOVAL, false);
632 }
633
634 NotifyMediaState(mp->mountPoint, MEDIA_REMOVED, false);
635 break;
636 }
637 mp = mp->next;
638 }
639}
640
641// Handle retrying to mount or unmount devices,
642// and handle timeout condition if we have tried too many times
643static void HandleRetries()
644{
645 MountPoint* mp = sMountPointList;
646
647 while (mp)
648 {
649 if (mp->state == kMounting)
650 {
651 if (MountPartition(mp->device, mp->mountPoint) == 0)
652 {
653 // mount succeeded - clear the retry for this mount point
654 ClearRetries(mp, kMounted);
655 }
656 else
657 {
658 mp->retryCount++;
659 if (mp->retryCount == MAX_MOUNT_RETRIES)
660 {
661 // we failed to mount the device too many times
662 ClearRetries(mp, kUnmounted);
663 // notify that we failed to mount
664 NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTABLE, false);
665 }
666 }
667 }
668 else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
669 {
670 if (DoUnmountDevice(mp) == 0)
671 {
672 // unmounting succeeded
673 // start mass storage, if state is kUnmountingForUms
674 if (mp->state == kUnmountingForUms)
675 {
676 SetBackingStore(mp, true);
677 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
678 }
679 // clear the retry for this mount point
680 ClearRetries(mp, kUnmounted);
681 }
682 else
683 {
684 mp->retryCount++;
685 if (mp->retryCount >= MAX_UNMOUNT_RETRIES)
686 {
687 // kill any processes that are preventing the device from unmounting
688 // send SIGKILL instead of SIGTERM if the first attempt did not succeed
689 boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
690
691 int i;
692
693 for (i = 0; i < ASEC_STORES_MAX; i++) {
694 if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
695 LOG_MOUNT("Killing processes for ASEC path '%s'\n",
696 AsecMountPoint(mp->asecHandles[i]));
697 KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
698 sigkill,
699 gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
700
701 // Now that we've killed the processes, try to stop the volume again
702 AsecStop(mp->asecHandles[i]);
703 }
704 }
705
706 // unmounting the device is failing, so start killing processes
707 KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids,
708 sizeof(gExcludedPids) / sizeof(pid_t));
709
710 }
711 }
712 }
713
714 mp = mp->next;
715 }
716}
717
718/*****************************************************
719 *
720 * AUTO-MOUNTER THREAD
721 *
722 *****************************************************/
723
724static void sigusr1_handler(int signo)
725{
726 // don't need to do anything here
727}
728
729// create a socket for listening to inotify events
730int CreateINotifySocket()
731{
732 // initialize inotify
733 int fd = inotify_init();
734
735 if (fd < 0) {
736 LOG_ERROR("inotify_init failed, %s\n", strerror(errno));
737 return -1;
738 }
739
740 fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
741
742 return fd;
743}
744
745
746// create a socket for listening to uevents
747int CreateUEventSocket()
748{
749 struct sockaddr_nl addr;
750 int sz = 64*1024;
751 int fd;
752
753 memset(&addr, 0, sizeof(addr));
754 addr.nl_family = AF_NETLINK;
755 addr.nl_pid = getpid();
756 addr.nl_groups = 0xffffffff;
757
758 fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
759 if(fd < 0)
760 {
761 LOG_ERROR("could not create NETLINK_KOBJECT_UEVENT socket\n");
762 return -1;
763 }
764
765 setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
766
767 if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
768 LOG_ERROR("could not bind NETLINK_KOBJECT_UEVENT socket\n");
769 close(fd);
770 return -1;
771 }
772
773 return fd;
774}
775
776/*
777 * Automounter main event thread.
778 * This thread listens for block devices being created and deleted via inotify,
779 * and listens for changes in the USB mass storage connected/disconnected via uevents from the
780 * power supply driver.
781 * This thread also handles retries and timeouts for requests to mount or unmount a device.
782 */
783static void* AutoMountThread(void* arg)
784{
785 int inotify_fd;
786 int uevent_fd;
787 int id;
788 struct sigaction actions;
789
790 gExcludedPids[1] = getpid();
791
792 memset(&actions, 0, sizeof(actions));
793 sigemptyset(&actions.sa_mask);
794 actions.sa_flags = 0;
795 actions.sa_handler = sigusr1_handler;
796 sigaction(SIGUSR1, &actions, NULL);
797
798 // initialize inotify
799 inotify_fd = CreateINotifySocket();
800 // watch for files created and deleted in "/dev"
801 inotify_add_watch(inotify_fd, DEVPATH, IN_CREATE|IN_DELETE);
802
803 // initialize uevent watcher
804 uevent_fd = CreateUEventSocket();
805 if (uevent_fd < 0)
806 {
807 LOG_ERROR("CreateUEventSocket failed, %s\n", strerror(errno));
808 return NULL;
809 }
810
811 while (1)
812 {
813 struct pollfd fds[2];
814 int timeout, result;
815
816#define INOTIFY_IDX 0
817#define UEVENT_IDX 1
818
819 fds[INOTIFY_IDX].fd = inotify_fd;
820 fds[INOTIFY_IDX].events = POLLIN;
821 fds[INOTIFY_IDX].revents = 0;
822 fds[UEVENT_IDX].fd = uevent_fd;
823 fds[UEVENT_IDX].events = POLLIN;
824 fds[UEVENT_IDX].revents = 0;
825
826 // wait for an event or a timeout to occur.
827 // poll() can also return in response to a SIGUSR1 signal
828 timeout = (sRetriesPending ? POLL_TIMEOUT : -1);
829 result = poll(fds, 2, timeout);
830
831 // lock the mutex while we are handling events
832 pthread_mutex_lock(&sMutex);
833
834 // handle inotify notifications for block device creation and deletion
835 if (fds[INOTIFY_IDX].revents == POLLIN)
836 {
837 struct inotify_event event;
838 char buffer[512];
839 int length = read(inotify_fd, buffer, sizeof(buffer));
840 int offset = 0;
841
842 while (length >= (int)sizeof(struct inotify_event))
843 {
844 struct inotify_event* event = (struct inotify_event *)&buffer[offset];
845
846 if (event->mask == IN_CREATE)
847 {
848 LOG_MOUNT("/dev/block/%s created\n", event->name);
849 HandleMediaInserted(event->name);
850 }
851 else if (event->mask == IN_DELETE)
852 {
853 LOG_MOUNT("/dev/block/%s deleted\n", event->name);
854 HandleMediaRemoved(event->name);
855 }
856
857 int size = sizeof(struct inotify_event) + event->len;
858 length -= size;
859 offset += size;
860 }
861 }
862
863 // handle uevent notifications for USB state changes
864 if (fds[UEVENT_IDX].revents == POLLIN)
865 {
866 char buffer[64*1024];
867 int count;
868
869 count = recv(uevent_fd, buffer, sizeof(buffer), 0);
870 if (count > 0) {
871 char* s = buffer;
872 char* end = s + count;
873 char* type = NULL;
874 char* online = NULL;
875 char* switchName = NULL;
876 char* switchState = NULL;
877
878 while (s < end) {
879 if (!strncmp("POWER_SUPPLY_TYPE=", s, strlen("POWER_SUPPLY_TYPE=")))
880 type = s + strlen("POWER_SUPPLY_TYPE=");
881 else if (!strncmp("POWER_SUPPLY_ONLINE=", s, strlen("POWER_SUPPLY_ONLINE=")))
882 online = s + strlen("POWER_SUPPLY_ONLINE=");
883 else if (!strncmp("SWITCH_NAME=", s, strlen("SWITCH_NAME=")))
884 switchName = s + strlen("SWITCH_NAME=");
885 else if (!strncmp("SWITCH_STATE=", s, strlen("SWITCH_STATE=")))
886 switchState = s + strlen("SWITCH_STATE=");
887 s += (strlen(s) + 1);
888 }
889
890 // we use the usb_mass_storage switch state to tell us when USB is online
891 if (switchName && switchState &&
892 !strcmp(switchName, "usb_mass_storage") && !strcmp(switchState, "online"))
893 {
894 LOG_MOUNT("USB online\n");
895 HandleMassStorageOnline(true);
896 }
897
898 // and we use the power supply state to tell us when USB is offline
899 // we can't rely on the switch for offline detection because we get false positives
900 // when USB is reenumerated by the host.
901 if (type && online && !strcmp(type, "USB") && !strcmp(online, "0"))
902 {
903 LOG_MOUNT("USB offline\n");
904 HandleMassStorageOnline(false);
905 }
906 }
907 }
908
909 // handle retries
910 if (sRetriesPending)
911 HandleRetries();
912
913 // done handling events, so unlock the mutex
914 pthread_mutex_unlock(&sMutex);
915 }
916
917 inotify_rm_watch(inotify_fd, id);
918 close(inotify_fd);
919 close(uevent_fd);
920
921 return NULL;
922}
923
924/*****************************************************
925 *
926 * THESE FUNCTIONS ARE CALLED FROM THE SERVER THREAD
927 *
928 *****************************************************/
929
930// Called to enable or disable USB mass storage support
931void EnableMassStorage(boolean enable)
932{
933 pthread_mutex_lock(&sMutex);
934
935 LOG_MOUNT("EnableMassStorage %s\n", (enable ? "true" : "false"));
936 gMassStorageEnabled = enable;
937 MassStorageStateChanged();
938 pthread_mutex_unlock(&sMutex);
939 }
940
941// Called to request that the specified mount point be mounted
942void MountMedia(const char* mountPoint)
943{
944 MountPoint* mp = sMountPointList;
945
946 LOG_MOUNT("MountMedia(%s)\n", mountPoint);
947
948 pthread_mutex_lock(&sMutex);
949 while (mp)
950 {
951 if (strcmp(mp->mountPoint, mountPoint) == 0)
952 {
953 if (mp->state == kUnmountingForEject)
954 {
955 // handle the case where we try to remount before we actually unmounted
956 ClearRetries(mp, kMounted);
957 }
958
959 // don't attempt to mount if mass storage is active
960 if (!MassStorageEnabledForMountPoint(mp))
961 RequestMount(mp);
962 }
963
964 mp = mp->next;
965 }
966 pthread_mutex_unlock(&sMutex);
967 }
968
969// Called to request that the specified mount point be unmounted
970void UnmountMedia(const char* mountPoint)
971{
972 MountPoint* mp = sMountPointList;
973
974 pthread_mutex_lock(&sMutex);
975 while (mp)
976 {
977 if (strcmp(mp->mountPoint, mountPoint) == 0)
978 RequestUnmount(mp, kUnmountingForEject);
979
980 mp = mp->next;
981 }
982 pthread_mutex_unlock(&sMutex);
983}
984
985boolean IsMassStorageEnabled()
986{
987 return gMassStorageEnabled;
988}
989
990boolean IsMassStorageConnected()
991{
992 return gMassStorageConnected;
993}
994
995/***********************************************
996 *
997 * THESE FUNCTIONS ARE CALLED ONLY AT STARTUP
998 *
999 ***********************************************/
1000
1001void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
1002{
1003 MountPoint* newMountPoint;
1004
1005 LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
1006 // add a new MountPoint to the head of our linked list
1007 newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
1008 newMountPoint->device = device;
1009 newMountPoint->mountPoint = mountPoint;
1010 newMountPoint->driverStorePath = driverStorePath;
1011 newMountPoint->enableUms = enableUms;
1012 newMountPoint->umsActive = false;
1013 newMountPoint->state = kUnmounted;
1014 newMountPoint->retryCount = 0;
1015
1016 // add to linked list
1017 newMountPoint->next = sMountPointList;
1018 sMountPointList = newMountPoint;
1019 return newMountPoint;
1020}
1021
1022int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
1023 const char *mount_point, const char *crypt)
1024{
1025 MountPoint *mp = (MountPoint *) Mp;
1026 int i;
1027
1028 for (i = 0; i < ASEC_STORES_MAX; i++) {
1029 if (!mp->asecHandles[i])
1030 break;
1031 }
1032
1033 if (i == ASEC_STORES_MAX) {
1034 LOG_ERROR("Maximum # of ASEC stores exceeded\n");
1035 return -EINVAL;
1036 }
1037
1038 if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
1039 return -1;
1040
1041 return 0;
1042}
1043static void MountDevices()
1044{
1045 MountPoint* mp = sMountPointList;
1046 while (mp)
1047 {
1048 RequestMount(mp);
1049 mp = mp->next;
1050 }
1051}
1052
1053void StartAutoMounter()
1054{
1055 gExcludedPids[0] = getpid();
1056
1057 gMassStorageConnected = ReadMassStorageState();
1058 LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
1059
1060 MountDevices();
1061 pthread_create(&sAutoMountThread, NULL, AutoMountThread, NULL);
1062}