270 lines
6.7 KiB
C
270 lines
6.7 KiB
C
|
|
/*
|
|
* 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;
|
|
}
|