auto import from //branches/cupcake/...@127101
diff --git a/vold/inotify.c b/vold/inotify.c
new file mode 100644
index 0000000..a7b789c
--- /dev/null
+++ b/vold/inotify.c
@@ -0,0 +1,270 @@
+
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/inotify.h>
+#include <sys/stat.h>
+
+#include "vold.h"
+#include "inotify.h"
+#include "blkdev.h"
+#include "volmgr.h"
+
+#define DEBUG_INOTIFY 0
+
+static int handle_inotify_event(struct inotify_event *evt);
+
+int process_inotify_event(int fd)
+{
+ char buffer[512];
+ int len;
+ int offset = 0;
+
+ if ((len = read(fd, buffer, sizeof(buffer))) < 0) {
+ LOGE("Unable to read inotify event (%m)\n");
+ return -errno;
+ }
+
+ while (len >= (int) sizeof(struct inotify_event)) {
+ struct inotify_event *evt = (struct inotify_event *) &buffer[offset];
+
+ if (handle_inotify_event(evt) < 0)
+ LOGE("Error handling inotify event (%m)\n");
+
+ len -= sizeof(struct inotify_event) + evt->len;
+ offset += sizeof(struct inotify_event) + evt->len;
+
+ }
+ return 0;
+}
+
+struct blk_dev_entry {
+ int minor;
+ char *name;
+ struct blk_dev_entry *next;
+};
+
+int inotify_bootstrap(void)
+{
+ DIR *d;
+ struct dirent *de;
+
+ if (!(d = opendir(DEVPATH))) {
+ LOGE("Unable to open directory '%s' (%m)\n", DEVPATH);
+ return -errno;
+ }
+
+ struct blk_dev_entry *blkdevs[255];
+
+ memset(blkdevs, 0, sizeof(blkdevs));
+
+ while((de = readdir(d))) {
+ char filename[255];
+ struct stat sbuf;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ sprintf(filename, "%s/%s", DEVPATH, de->d_name);
+
+ if (stat(filename, &sbuf) < 0) {
+ LOGE("Unable to stat '%s' (%m)\n", filename);
+ continue;
+ }
+
+ if (!S_ISBLK(sbuf.st_mode))
+ continue;
+
+
+ int major = (sbuf.st_rdev & 0xfff00) >> 8;
+ int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
+
+ struct blk_dev_entry *entry;
+
+ if (!(entry = malloc(sizeof(struct blk_dev_entry)))) {
+ LOGE("Out of memory\n");
+ break;
+ }
+ entry->minor = minor;
+ entry->name = strdup(de->d_name);
+ entry->next = NULL;
+
+ if (!blkdevs[major])
+ blkdevs[major] = entry;
+ else {
+ struct blk_dev_entry *scan = blkdevs[major];
+
+ /*
+ * Insert the entry in minor number ascending order
+ */
+ while(scan) {
+ if (minor < scan->minor) {
+ entry->next = scan;
+
+ if (scan == blkdevs[major])
+ blkdevs[major] = entry;
+ else
+ scan->next = entry;
+ break;
+ }
+ scan = scan->next;
+ }
+ if (!scan) {
+ scan = blkdevs[major];
+ while(scan->next)
+ scan = scan->next;
+ scan->next = entry;
+ }
+ }
+
+ }
+
+ closedir(d);
+
+ int i = 0;
+
+ for (i = 0; i < 255; i++) {
+ if (!blkdevs[i])
+ continue;
+ struct blk_dev_entry *scan = blkdevs[i];
+
+ while(scan) {
+ struct inotify_event *evt;
+ int len;
+
+ len = sizeof(struct inotify_event) + strlen(scan->name);
+
+ if (!(evt = malloc(len))) {
+ LOGE("Out of memory\n");
+ break;
+ }
+ memset(evt, 0, len);
+ strcpy(evt->name, scan->name);
+ evt->mask = IN_CREATE;
+
+ if (handle_inotify_event(evt) < 0)
+ LOGE("Error handling bootstrapped inotify event (%m)\n");
+ free(evt);
+
+ scan = scan->next;
+ }
+ }
+
+ for (i = 0; i < 255; i++) {
+ if (!blkdevs[i])
+ continue;
+
+ if (!blkdevs[i]->next) {
+ free(blkdevs[i]->name);
+ free(blkdevs[i]);
+ blkdevs[i] = NULL;
+ continue;
+ }
+
+ struct blk_dev_entry *scan = blkdevs[i];
+ while(scan) {
+ struct blk_dev_entry *next = scan->next->next;
+
+ free(scan->next->name);
+ free(scan->next);
+
+ scan->next = next;
+ scan = next;
+ }
+
+ } // for
+
+
+ return 0;
+}
+
+static int handle_inotify_event(struct inotify_event *evt)
+{
+ char filename[255];
+ int rc;
+
+#if DEBUG_INOTIFY
+ LOG_VOL("Inotify '%s' %s\n", evt->name, (evt->mask == IN_CREATE ? "created" : "deleted"));
+#endif
+
+ sprintf(filename, "%s%s", DEVPATH, evt->name);
+
+ if (evt->mask == IN_CREATE) {
+ struct stat sbuf;
+
+ if (stat(filename, &sbuf) < 0) {
+ LOGE("Unable to stat '%s' (%m)\n", filename);
+ return -errno;
+ }
+
+ if (!S_ISBLK(sbuf.st_mode)) {
+#if DEBUG_INOTIFY
+ LOG_VOL("Ignoring inotify on '%s' (not a block device)\n", evt->name);
+#endif
+ return 0;
+ }
+
+ int major = (sbuf.st_rdev & 0xfff00) >> 8;
+ int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
+
+ blkdev_t *blkdev = blkdev_lookup_by_devno(major, minor);
+
+ if ((rc = blkdev_handle_devicefile_created(blkdev, filename)) < 0) {
+ LOGE("Error handling device file '%s' creation (%s)\n", filename, strerror(rc));
+ return rc;
+ }
+
+ if (!blkdev) {
+#if DEBUG_INOTIFY
+ LOG_VOL("No backing blkdev for '%s' available (yet) - pending volmgr dispatch\n", filename);
+#endif
+ return 0;
+ }
+
+#if DEBUG_INOTIFY
+ LOG_VOL("NUM_PENDING_PARTITIONS = %d\n", blkdev_get_num_pending_partitions(blkdev));
+#endif
+ if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
+ if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
+ LOGE("Error from volmgr - %d\n", rc);
+ return rc;
+ }
+ }
+ } else {
+ blkdev_t *blkdev;
+
+ if (!(blkdev = blkdev_lookup_by_dev_fspath(filename))) {
+#if DEBUG_INOTIFY
+ LOG_VOL("Ignoring removal of '%s' (no backend blkdev)\n", filename);
+#endif
+ return 0;
+ }
+
+ if ((rc = blkdev_handle_devicefile_removed(blkdev, filename)) < 0) {
+ LOGE("Error handling device file '%s' removal (%s)\n", filename, strerror(rc));
+ return rc;
+ }
+ }
+
+ return 0;
+}