auto import from //branches/cupcake/...@127101
This commit is contained in:
parent
2eef60297a
commit
8ac3a13816
|
@ -25,7 +25,7 @@
|
|||
void die(const char *why, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
||||
va_start(ap, why);
|
||||
fprintf(stderr,"error: ");
|
||||
vfprintf(stderr, why, ap);
|
||||
|
@ -44,6 +44,11 @@ static void fix_stat(const char *path, struct stat *s)
|
|||
|
||||
static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
|
||||
{
|
||||
// Nothing is special about this value, just picked something in the
|
||||
// approximate range that was being used already, and avoiding small
|
||||
// values which may be special.
|
||||
static unsigned next_inode = 300000;
|
||||
|
||||
while(total_size & 3) {
|
||||
total_size++;
|
||||
putchar(0);
|
||||
|
@ -55,12 +60,12 @@ static void _eject(struct stat *s, char *out, int olen, char *data, unsigned dat
|
|||
printf("%06x%08x%08x%08x%08x%08x%08x"
|
||||
"%08x%08x%08x%08x%08x%08x%08x%s%c",
|
||||
0x070701,
|
||||
(unsigned) s->st_ino,
|
||||
next_inode++, // s.st_ino,
|
||||
s->st_mode,
|
||||
0, // s.st_uid,
|
||||
0, // s.st_gid,
|
||||
1, // s.st_nlink,
|
||||
(unsigned) s->st_mtime,
|
||||
0, // s.st_mtime,
|
||||
datasize,
|
||||
0, // volmajor
|
||||
0, // volminor
|
||||
|
@ -75,7 +80,7 @@ static void _eject(struct stat *s, char *out, int olen, char *data, unsigned dat
|
|||
total_size += 6 + 8*13 + olen + 1;
|
||||
|
||||
if(strlen(out) != olen) die("ACK!");
|
||||
|
||||
|
||||
while(total_size & 3) {
|
||||
total_size++;
|
||||
putchar(0);
|
||||
|
@ -101,9 +106,13 @@ static void _eject_trailer()
|
|||
|
||||
static void _archive(char *in, char *out, int ilen, int olen);
|
||||
|
||||
static int compare(const void* a, const void* b) {
|
||||
return strcmp(*(const char**)a, *(const char**)b);
|
||||
}
|
||||
|
||||
static void _archive_dir(char *in, char *out, int ilen, int olen)
|
||||
{
|
||||
int t;
|
||||
int i, t;
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
|
@ -111,33 +120,65 @@ static void _archive_dir(char *in, char *out, int ilen, int olen)
|
|||
fprintf(stderr,"_archive_dir('%s','%s',%d,%d)\n",
|
||||
in, out, ilen, olen);
|
||||
}
|
||||
|
||||
|
||||
d = opendir(in);
|
||||
if(d == 0) die("cannot open directory '%s'", in);
|
||||
|
||||
|
||||
int size = 32;
|
||||
int entries = 0;
|
||||
char** names = malloc(size * sizeof(char*));
|
||||
if (names == NULL) {
|
||||
fprintf(stderr, "failed to allocate dir names array (size %d)\n", size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while((de = readdir(d)) != 0){
|
||||
/* xxx: feature? maybe some dotfiles are okay */
|
||||
if(de->d_name[0] == '.') continue;
|
||||
|
||||
/* xxx: hack. use a real exclude list */
|
||||
if(!strcmp(de->d_name, "root")) continue;
|
||||
|
||||
t = strlen(de->d_name);
|
||||
|
||||
if (entries >= size) {
|
||||
size *= 2;
|
||||
names = realloc(names, size * sizeof(char*));
|
||||
if (names == NULL) {
|
||||
fprintf(stderr, "failed to reallocate dir names array (size %d)\n",
|
||||
size);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
names[entries] = strdup(de->d_name);
|
||||
if (names[entries] == NULL) {
|
||||
fprintf(stderr, "failed to strdup name \"%s\"\n",
|
||||
de->d_name);
|
||||
exit(1);
|
||||
}
|
||||
++entries;
|
||||
}
|
||||
|
||||
qsort(names, entries, sizeof(char*), compare);
|
||||
|
||||
for (i = 0; i < entries; ++i) {
|
||||
t = strlen(names[i]);
|
||||
in[ilen] = '/';
|
||||
memcpy(in + ilen + 1, de->d_name, t + 1);
|
||||
memcpy(in + ilen + 1, names[i], t + 1);
|
||||
|
||||
if(olen > 0) {
|
||||
out[olen] = '/';
|
||||
memcpy(out + olen + 1, de->d_name, t + 1);
|
||||
memcpy(out + olen + 1, names[i], t + 1);
|
||||
_archive(in, out, ilen + t + 1, olen + t + 1);
|
||||
} else {
|
||||
memcpy(out, de->d_name, t + 1);
|
||||
memcpy(out, names[i], t + 1);
|
||||
_archive(in, out, ilen + t + 1, t);
|
||||
}
|
||||
|
||||
in[ilen] = 0;
|
||||
out[olen] = 0;
|
||||
|
||||
free(names[i]);
|
||||
}
|
||||
free(names);
|
||||
}
|
||||
|
||||
static void _archive(char *in, char *out, int ilen, int olen)
|
||||
|
@ -148,7 +189,7 @@ static void _archive(char *in, char *out, int ilen, int olen)
|
|||
fprintf(stderr,"_archive('%s','%s',%d,%d)\n",
|
||||
in, out, ilen, olen);
|
||||
}
|
||||
|
||||
|
||||
if(lstat(in, &s)) die("could not stat '%s'\n", in);
|
||||
|
||||
if(S_ISREG(s.st_mode)){
|
||||
|
@ -166,7 +207,7 @@ static void _archive(char *in, char *out, int ilen, int olen)
|
|||
}
|
||||
|
||||
_eject(&s, out, olen, tmp, s.st_size);
|
||||
|
||||
|
||||
free(tmp);
|
||||
close(fd);
|
||||
} else if(S_ISDIR(s.st_mode)) {
|
||||
|
@ -208,13 +249,13 @@ int main(int argc, char *argv[])
|
|||
} else {
|
||||
x = "";
|
||||
}
|
||||
|
||||
|
||||
archive(*argv, x);
|
||||
|
||||
argv++;
|
||||
}
|
||||
|
||||
_eject_trailer();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef NATIVE_HANDLE_H_
|
||||
#define NATIVE_HANDLE_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int version; /* sizeof(native_handle) */
|
||||
int numFds; /* number of file-descriptors at &data[0] */
|
||||
int numInts; /* number of ints at &data[numFds] */
|
||||
int data[0]; /* numFds + numInts ints */
|
||||
} native_handle;
|
||||
|
||||
#endif /* NATIVE_HANDLE_H_ */
|
|
@ -7,5 +7,12 @@ LOCAL_MODULE := libmincrypt
|
|||
LOCAL_SRC_FILES := rsa.c sha.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libmincrypt
|
||||
LOCAL_SRC_FILES := rsa.c sha.c
|
||||
include $(BUILD_HOST_STATIC_LIBRARY)
|
||||
|
||||
|
||||
# TODO: drop the hyphen once these are checked in
|
||||
include $(LOCAL_PATH)/tools/Android.mk
|
||||
|
|
|
@ -3,6 +3,7 @@ LOCAL_PATH:= $(call my-dir)
|
|||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := mkbootimg.c
|
||||
LOCAL_STATIC_LIBRARIES := libmincrypt
|
||||
|
||||
LOCAL_MODULE := mkbootimg
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
**
|
||||
** Copyright 2007, 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
|
||||
** 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
|
||||
** 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
|
||||
** 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.
|
||||
*/
|
||||
|
||||
|
@ -21,8 +21,8 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mincrypt/sha.h"
|
||||
#include "bootimg.h"
|
||||
|
||||
static void *load_file(const char *fn, unsigned *_sz)
|
||||
|
@ -82,7 +82,7 @@ int write_padding(int fd, unsigned pagesize, unsigned itemsize)
|
|||
}
|
||||
|
||||
count = pagesize - (itemsize & pagemask);
|
||||
|
||||
|
||||
if(write(fd, padding, count) != count) {
|
||||
return -1;
|
||||
} else {
|
||||
|
@ -90,21 +90,10 @@ int write_padding(int fd, unsigned pagesize, unsigned itemsize)
|
|||
}
|
||||
}
|
||||
|
||||
unsigned checksum(void *_ptr, unsigned len)
|
||||
{
|
||||
unsigned chk = 0;
|
||||
unsigned char *ptr = _ptr;
|
||||
while (len > 0) {
|
||||
chk += *ptr++;
|
||||
len--;
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
boot_img_hdr hdr;
|
||||
|
||||
|
||||
char *kernel_fn = 0;
|
||||
void *kernel_data = 0;
|
||||
char *ramdisk_fn = 0;
|
||||
|
@ -117,12 +106,14 @@ int main(int argc, char **argv)
|
|||
unsigned pagesize = 2048;
|
||||
unsigned saddr = 0;
|
||||
int fd;
|
||||
|
||||
SHA_CTX ctx;
|
||||
uint8_t* sha;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
|
||||
|
||||
while(argc > 0){
|
||||
char *arg = argv[0];
|
||||
char *val = argv[1];
|
||||
|
@ -171,7 +162,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
strcpy(hdr.name, board);
|
||||
|
||||
|
||||
hdr.kernel_addr = 0x10008000;
|
||||
hdr.ramdisk_addr = 0x11000000;
|
||||
if(saddr) {
|
||||
|
@ -181,21 +172,21 @@ int main(int argc, char **argv)
|
|||
}
|
||||
hdr.tags_addr = 0x10000100;
|
||||
hdr.page_size = pagesize;
|
||||
|
||||
|
||||
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
|
||||
|
||||
|
||||
if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
|
||||
fprintf(stderr,"error: kernel commandline too large\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy((char*)hdr.cmdline, cmdline);
|
||||
|
||||
|
||||
kernel_data = load_file(kernel_fn, &hdr.kernel_size);
|
||||
if(kernel_data == 0) {
|
||||
fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if(!strcmp(ramdisk_fn,"NONE")) {
|
||||
ramdisk_data = 0;
|
||||
hdr.ramdisk_size = 0;
|
||||
|
@ -215,15 +206,19 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
/* put some stuff in the header to differentiate between
|
||||
* different boot images. SHA1 would be nicer, but this
|
||||
* isn't for crypto grade anything, just to have a quick
|
||||
* way to compare boot.imgs based on their first 2k
|
||||
*/
|
||||
hdr.id[0] = (unsigned) time(0);
|
||||
hdr.id[1] = checksum(kernel_data, hdr.kernel_size);
|
||||
hdr.id[2] = checksum(ramdisk_data, hdr.ramdisk_size);
|
||||
hdr.id[3] = checksum(second_data, hdr.second_size);
|
||||
/* put a hash of the contents in the header so boot images can be
|
||||
* differentiated based on their first 2k.
|
||||
*/
|
||||
SHA_init(&ctx);
|
||||
SHA_update(&ctx, kernel_data, hdr.kernel_size);
|
||||
SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
|
||||
SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
|
||||
SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
|
||||
SHA_update(&ctx, second_data, hdr.second_size);
|
||||
SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
|
||||
sha = SHA_final(&ctx);
|
||||
memcpy(hdr.id, sha,
|
||||
SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
|
||||
|
||||
fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
|
||||
if(fd < 0) {
|
||||
|
@ -246,7 +241,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
fail:
|
||||
unlink(bootimg);
|
||||
close(fd);
|
||||
|
@ -254,4 +249,3 @@ fail:
|
|||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -289,6 +289,7 @@ static int DoMountDevice(const char* device, const char* mountPoint)
|
|||
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:
|
||||
|
@ -298,6 +299,7 @@ static int DoMountDevice(const char* device, const char* mountPoint)
|
|||
// - SD cards with bad filesystem
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Extra safety measures:
|
||||
flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
BUILD_VOLD := false
|
||||
|
||||
ifeq ($(BUILD_VOLD),true)
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
vold.c \
|
||||
cmd_dispatch.c \
|
||||
uevent.c \
|
||||
inotify.c \
|
||||
mmc.c \
|
||||
misc.c \
|
||||
blkdev.c \
|
||||
ums.c \
|
||||
geom_mbr_enc.c \
|
||||
volmgr.c \
|
||||
media.c \
|
||||
volmgr_vfat.c \
|
||||
volmgr_ext3.c \
|
||||
logwrapper.c \
|
||||
ProcessKiller.c\
|
||||
|
||||
LOCAL_MODULE:= vold
|
||||
|
||||
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
|
||||
|
||||
LOCAL_CFLAGS :=
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libcutils
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* 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 process killer
|
||||
*/
|
||||
|
||||
#include "vold.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
static boolean ReadSymLink(const char* path, char* link)
|
||||
{
|
||||
struct stat s;
|
||||
int length;
|
||||
|
||||
if (lstat(path, &s) < 0)
|
||||
return false;
|
||||
if ((s.st_mode & S_IFMT) != S_IFLNK)
|
||||
return false;
|
||||
|
||||
// we have a symlink
|
||||
length = readlink(path, link, PATH_MAX - 1);
|
||||
if (length <= 0)
|
||||
return false;
|
||||
link[length] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean PathMatchesMountPoint(const char* path, const char* mountPoint)
|
||||
{
|
||||
int length = strlen(mountPoint);
|
||||
if (length > 1 && strncmp(path, mountPoint, length) == 0)
|
||||
{
|
||||
// we need to do extra checking if mountPoint does not end in a '/'
|
||||
if (mountPoint[length - 1] == '/')
|
||||
return true;
|
||||
// if mountPoint does not have a trailing slash, we need to make sure
|
||||
// there is one in the path to avoid partial matches.
|
||||
return (path[length] == 0 || path[length] == '/');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void GetProcessName(int pid, char buffer[PATH_MAX])
|
||||
{
|
||||
int fd;
|
||||
sprintf(buffer, "/proc/%d/cmdline", pid);
|
||||
fd = open(buffer, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
strcpy(buffer, "???");
|
||||
} else {
|
||||
int length = read(fd, buffer, PATH_MAX - 1);
|
||||
buffer[length] = 0;
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
|
||||
{
|
||||
DIR* dir;
|
||||
struct dirent* de;
|
||||
boolean fileOpen = false;
|
||||
char path[PATH_MAX];
|
||||
char link[PATH_MAX];
|
||||
int parent_length;
|
||||
|
||||
// compute path to process's directory of open files
|
||||
sprintf(path, "/proc/%d/fd", pid);
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
// remember length of the path
|
||||
parent_length = strlen(path);
|
||||
// append a trailing '/'
|
||||
path[parent_length++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != 0 && !fileOpen) {
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// append the file name, after truncating to parent directory
|
||||
path[parent_length] = 0;
|
||||
strcat(path, de->d_name);
|
||||
|
||||
if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
GetProcessName(pid, name);
|
||||
LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link);
|
||||
fileOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return fileOpen;
|
||||
}
|
||||
|
||||
static boolean CheckFileMaps(int pid, const char* mountPoint)
|
||||
{
|
||||
FILE* file;
|
||||
char buffer[PATH_MAX + 100];
|
||||
boolean mapOpen = false;
|
||||
|
||||
sprintf(buffer, "/proc/%d/maps", pid);
|
||||
file = fopen(buffer, "r");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
while (!mapOpen && fgets(buffer, sizeof(buffer), file))
|
||||
{
|
||||
// skip to the path
|
||||
const char* path = strchr(buffer, '/');
|
||||
if (path && PathMatchesMountPoint(path, mountPoint))
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
GetProcessName(pid, name);
|
||||
LOG_ERROR("process %s (%d) has open file map for %s\n", name, pid, path);
|
||||
mapOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return mapOpen;
|
||||
}
|
||||
|
||||
static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char link[PATH_MAX];
|
||||
|
||||
sprintf(path, "/proc/%d/%s", pid, name);
|
||||
if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
GetProcessName(pid, name);
|
||||
LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int get_pid(const char* s)
|
||||
{
|
||||
int result = 0;
|
||||
while (*s) {
|
||||
if (!isdigit(*s)) return -1;
|
||||
result = 10 * result + (*s++ - '0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// hunt down and kill processes that have files open on the given mount point
|
||||
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
|
||||
{
|
||||
DIR* dir;
|
||||
struct dirent* de;
|
||||
|
||||
LOG_ERROR("KillProcessesWithOpenFiles %s\n", mountPoint);
|
||||
dir = opendir("/proc");
|
||||
if (!dir) return;
|
||||
|
||||
while ((de = readdir(dir)) != 0)
|
||||
{
|
||||
boolean killed = false;
|
||||
// does the name look like a process ID?
|
||||
int pid = get_pid(de->d_name);
|
||||
if (pid == -1) continue;
|
||||
|
||||
if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files
|
||||
|| CheckFileMaps(pid, mountPoint) // check for mmap()
|
||||
|| CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory
|
||||
|| CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot()
|
||||
|| CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
|
||||
)
|
||||
{
|
||||
int i;
|
||||
boolean hit = false;
|
||||
|
||||
for (i = 0; i < num_excluded; i++) {
|
||||
if (pid == excluded[i]) {
|
||||
LOG_ERROR("I just need a little more TIME captain!\n");
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hit) {
|
||||
LOG_ERROR("Killing process %d\n", pid);
|
||||
kill(pid, (sigkill ? SIGKILL : SIGTERM));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
|
||||
/*
|
||||
* 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 <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "blkdev.h"
|
||||
#include "diskmbr.h"
|
||||
|
||||
#define DEBUG_BLKDEV 0
|
||||
|
||||
static blkdev_list_t *list_root = NULL;
|
||||
|
||||
static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
|
||||
int minor, char *type, struct media *media, char *dev_fspath);
|
||||
static void blkdev_dev_fspath_set(blkdev_t *blk, char *dev_fspath);
|
||||
|
||||
int blkdev_handle_devicefile_removed(blkdev_t *blk, char *dev_fspath)
|
||||
{
|
||||
#if DEBUG_BLKDEV
|
||||
LOG_VOL("blkdev_handle_devicefile_removed(%s):\n", dev_fspath);
|
||||
#endif
|
||||
blkdev_dev_fspath_set(blk, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blkdev_handle_devicefile_created(blkdev_t *blk, char *dev_fspath)
|
||||
{
|
||||
int rc = 0;
|
||||
blkdev_t *disk;
|
||||
|
||||
#if DEBUG_BLKDEV
|
||||
LOG_VOL("blkdev_handle_devicefile_created(%s):\n", dev_fspath);
|
||||
#endif
|
||||
|
||||
if (!blk) {
|
||||
/*
|
||||
* This device does not yet have a backing blkdev associated with it.
|
||||
* Create a new one in the pending state and fill in the information
|
||||
* we have.
|
||||
*/
|
||||
struct stat sbuf;
|
||||
|
||||
if (stat(dev_fspath, &sbuf) < 0) {
|
||||
LOGE("Unable to stat device '%s' (%s)\n", dev_fspath, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int major = (sbuf.st_rdev & 0xfff00) >> 8;
|
||||
int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
|
||||
|
||||
disk = blkdev_lookup_by_devno(major, 0);
|
||||
|
||||
if (!disk) {
|
||||
/*
|
||||
* If there isn't a disk associated with this device, then
|
||||
* its not what we're looking for
|
||||
*/
|
||||
#if DEBUG_BLKDEV
|
||||
LOG_VOL("Ignoring device file '%s' (no disk found)\n", dev_fspath);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(blk = blkdev_create_pending_partition(disk, dev_fspath, major,
|
||||
minor, disk->media))) {
|
||||
LOGE("Unable to create pending blkdev\n");
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
blkdev_dev_fspath_set(blk, dev_fspath);
|
||||
|
||||
/*
|
||||
* If we're a disk, then read the partition table. Otherwise we're
|
||||
* a partition so get the partition type
|
||||
*/
|
||||
disk = blk->disk;
|
||||
|
||||
int fd;
|
||||
|
||||
if ((fd = open(disk->dev_fspath, O_RDWR)) < 0) {
|
||||
LOGE("Unable to open device '%s' (%s)\n", disk->dev_fspath, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE, &blk->nr_sec)) {
|
||||
LOGE("Unable to get device size (%m)\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
#if DEBUG_BLKDEV
|
||||
LOG_VOL("New device '%s' size = %u sectors\n", dev_fspath, blk->nr_sec);
|
||||
#endif
|
||||
|
||||
void *raw_pt;
|
||||
unsigned char *chr_pt;
|
||||
int i;
|
||||
|
||||
raw_pt = chr_pt = mmap(NULL, 512, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (raw_pt == MAP_FAILED) {
|
||||
LOGE("Unable to mmap device paritition table (%m)\n");
|
||||
goto out_nommap;
|
||||
}
|
||||
|
||||
if (blk->type == blkdev_disk) {
|
||||
blk->nr_parts = 0;
|
||||
|
||||
if ((chr_pt[0x1fe] != 0x55) && (chr_pt[0x1ff] != 0xAA)) {
|
||||
LOG_VOL("Disk '%s' does not contain a partition table\n", dev_fspath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
struct dos_partition part;
|
||||
|
||||
dos_partition_dec(raw_pt + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
|
||||
if (part.dp_size != 0 && part.dp_typ != 0)
|
||||
blk->nr_parts++;
|
||||
}
|
||||
LOG_VOL("Disk device '%s' (blkdev %s) contains %d partitions\n",
|
||||
dev_fspath, blk->devpath, blk->nr_parts);
|
||||
} else if (blk->type == blkdev_partition) {
|
||||
struct dos_partition part;
|
||||
int part_no = blk->minor -1;
|
||||
|
||||
dos_partition_dec(raw_pt + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
|
||||
|
||||
if (!part.dp_typ)
|
||||
LOG_VOL("Warning - Partition device '%s' (blkdev %s) has no partition type set\n",
|
||||
dev_fspath, blk->devpath);
|
||||
blk->part_type = part.dp_typ;
|
||||
|
||||
LOG_VOL("Partition device '%s' (blkdev %s) partition type 0x%x\n",
|
||||
dev_fspath, blk->devpath, blk->part_type);
|
||||
} else {
|
||||
LOGE("Bad blkdev type '%d'\n", blk->type);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
munmap(raw_pt, 512);
|
||||
out_nommap:
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
blkdev_t *blkdev_create_pending_partition(blkdev_t *disk, char *dev_fspath, int major,
|
||||
int minor, struct media *media)
|
||||
{
|
||||
return _blkdev_create(disk, NULL, major, minor, "partition", media, dev_fspath);
|
||||
}
|
||||
|
||||
blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type)
|
||||
{
|
||||
return _blkdev_create(disk, devpath, major, minor, type, media, NULL);
|
||||
}
|
||||
|
||||
static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
|
||||
int minor, char *type, struct media *media, char *dev_fspath)
|
||||
{
|
||||
blkdev_t *new;
|
||||
struct blkdev_list *list_entry;
|
||||
|
||||
if (disk && disk->type != blkdev_disk) {
|
||||
LOGE("Non disk parent specified for blkdev!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(new = malloc(sizeof(blkdev_t))))
|
||||
return NULL;
|
||||
|
||||
memset(new, 0, sizeof(blkdev_t));
|
||||
|
||||
if (!(list_entry = malloc(sizeof(struct blkdev_list)))) {
|
||||
free (new);
|
||||
return NULL;
|
||||
}
|
||||
list_entry->dev = new;
|
||||
list_entry->next = NULL;
|
||||
|
||||
if (!list_root)
|
||||
list_root = list_entry;
|
||||
else {
|
||||
struct blkdev_list *list_scan = list_root;
|
||||
while (list_scan->next)
|
||||
list_scan = list_scan->next;
|
||||
list_scan->next = list_entry;
|
||||
}
|
||||
|
||||
if (devpath)
|
||||
new->devpath = strdup(devpath);
|
||||
new->major = major;
|
||||
new->minor = minor;
|
||||
new->media = media;
|
||||
if (dev_fspath)
|
||||
new->dev_fspath = strdup(dev_fspath);
|
||||
new->nr_sec = 0xffffffff;
|
||||
|
||||
if (disk)
|
||||
new->disk = disk;
|
||||
else
|
||||
new->disk = new; // Note the self disk pointer
|
||||
|
||||
if (!strcmp(type, "disk"))
|
||||
new->type = blkdev_disk;
|
||||
else if (!strcmp(type, "partition"))
|
||||
new->type = blkdev_partition;
|
||||
else {
|
||||
LOGE("Unknown block device type '%s'\n", type);
|
||||
new->type = blkdev_unknown;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void blkdev_destroy(blkdev_t *blkdev)
|
||||
{
|
||||
struct blkdev_list *list_next;
|
||||
|
||||
if (list_root->dev == blkdev) {
|
||||
list_next = list_root->next;
|
||||
free (list_root);
|
||||
list_root = list_next;
|
||||
} else {
|
||||
struct blkdev_list *list_scan = list_root;
|
||||
while (list_scan->next->dev != blkdev)
|
||||
list_scan = list_scan -> next;
|
||||
list_next = list_scan->next->next;
|
||||
free(list_scan->next);
|
||||
list_scan->next = list_next;
|
||||
}
|
||||
|
||||
if (blkdev->devpath)
|
||||
free(blkdev->devpath);
|
||||
if (blkdev->dev_fspath)
|
||||
free(blkdev->dev_fspath);
|
||||
free(blkdev);
|
||||
}
|
||||
|
||||
blkdev_t *blkdev_lookup_by_path(char *devpath)
|
||||
{
|
||||
struct blkdev_list *list_scan = list_root;
|
||||
|
||||
while (list_scan) {
|
||||
if (!strcmp(list_scan->dev->devpath, devpath))
|
||||
return list_scan->dev;
|
||||
list_scan = list_scan->next;
|
||||
}
|
||||
#if DEBUG_BLKDEV
|
||||
LOG_VOL("blkdev_lookup_by_path(): No blkdev found @ %s\n", devpath);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blkdev_t *blkdev_lookup_by_devno(int maj, int min)
|
||||
{
|
||||
struct blkdev_list *list_scan = list_root;
|
||||
|
||||
while (list_scan) {
|
||||
if ((list_scan->dev->major == maj) &&
|
||||
(list_scan->dev->minor == min))
|
||||
return list_scan->dev;
|
||||
list_scan = list_scan->next;
|
||||
}
|
||||
#if DEBUG_BLKDEV
|
||||
LOG_VOL("blkdev_lookup_by_devno(): No blkdev found for %d.%d\n", maj, min);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blkdev_t *blkdev_lookup_by_dev_fspath(char *dev_fspath)
|
||||
{
|
||||
struct blkdev_list *list_scan = list_root;
|
||||
|
||||
while (list_scan) {
|
||||
if (list_scan->dev->dev_fspath) {
|
||||
if (!strcmp(list_scan->dev->dev_fspath, dev_fspath))
|
||||
return list_scan->dev;
|
||||
}
|
||||
|
||||
list_scan = list_scan->next;
|
||||
}
|
||||
// LOG_VOL("blkdev_lookup_by_devno(): No blkdev found for %d.%d\n", maj, min);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a disk device, return the number of partitions yet to be
|
||||
* processed.
|
||||
*/
|
||||
int blkdev_get_num_pending_partitions(blkdev_t *blk)
|
||||
{
|
||||
struct blkdev_list *list_scan = list_root;
|
||||
int num = blk->nr_parts;
|
||||
|
||||
if (blk->type != blkdev_disk)
|
||||
return -EINVAL;
|
||||
|
||||
while (list_scan) {
|
||||
if (list_scan->dev->type != blkdev_partition)
|
||||
goto next;
|
||||
|
||||
if (list_scan->dev->major != blk->major)
|
||||
goto next;
|
||||
|
||||
if (list_scan->dev->nr_sec != 0xffffffff)
|
||||
num--;
|
||||
next:
|
||||
list_scan = list_scan->next;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
void blkdev_devpath_set(blkdev_t *blk, char *devpath)
|
||||
{
|
||||
blk->devpath = strdup(devpath);
|
||||
}
|
||||
|
||||
static void blkdev_dev_fspath_set(blkdev_t *blk, char *dev_fspath)
|
||||
{
|
||||
if (dev_fspath)
|
||||
blk->dev_fspath = strdup(dev_fspath);
|
||||
else {
|
||||
free(blk->dev_fspath);
|
||||
blk->dev_fspath = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BLKDEV_H
|
||||
#define _BLKDEV_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct media;
|
||||
|
||||
enum blk_type { blkdev_unknown, blkdev_disk, blkdev_partition };
|
||||
|
||||
struct blkdev {
|
||||
char *devpath;
|
||||
enum blk_type type;
|
||||
struct media *media;
|
||||
|
||||
// If type == blkdev_disk then nr_parts = number of partitions
|
||||
int nr_parts;
|
||||
|
||||
// If type == blkdev_partition then part_type = partition type
|
||||
uint8_t part_type;
|
||||
// If type == blkdev_partition
|
||||
struct blkdev *disk;
|
||||
|
||||
unsigned int nr_sec;
|
||||
|
||||
int major;
|
||||
int minor;
|
||||
char *dev_fspath;
|
||||
};
|
||||
|
||||
struct blkdev_list {
|
||||
struct blkdev *dev;
|
||||
struct blkdev_list *next;
|
||||
};
|
||||
|
||||
typedef struct blkdev blkdev_t;
|
||||
typedef struct blkdev_list blkdev_list_t;
|
||||
|
||||
blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type);
|
||||
blkdev_t *blkdev_create_pending_partition(blkdev_t *disk, char *dev_fspath, int major, int minor, struct media *media);
|
||||
blkdev_t *blkdev_lookup_by_path(char *devpath);
|
||||
blkdev_t *blkdev_lookup_by_devno(int maj, int min);
|
||||
blkdev_t *blkdev_lookup_by_dev_fspath(char *dev_fspath);
|
||||
void blkdev_destroy(blkdev_t *blk);
|
||||
|
||||
int blkdev_handle_devicefile_created(blkdev_t *blk, char *dev_fspath);
|
||||
int blkdev_handle_devicefile_removed(blkdev_t *blk, char *dev_fspath);
|
||||
int blkdev_get_num_pending_partitions(blkdev_t *blk);
|
||||
void blkdev_devpath_set(blkdev_t *blk, char *dev_fspath);
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
/*
|
||||
* 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "cmd_dispatch.h"
|
||||
#include "ums.h"
|
||||
#include "volmgr.h"
|
||||
|
||||
struct cmd_dispatch {
|
||||
char *cmd;
|
||||
int (* dispatch) (char *);
|
||||
};
|
||||
|
||||
static void dispatch_cmd(char *cmd);
|
||||
static int do_send_ums_status(char *cmd);
|
||||
static int do_set_ums_enable(char *cmd);
|
||||
static int do_mount_volume(char *cmd);
|
||||
static int do_eject_media(char *cmd);
|
||||
|
||||
static struct cmd_dispatch dispatch_table[] = {
|
||||
{ VOLD_CMD_ENABLE_UMS, do_set_ums_enable },
|
||||
{ VOLD_CMD_DISABLE_UMS, do_set_ums_enable },
|
||||
{ VOLD_CMD_SEND_UMS_STATUS, do_send_ums_status },
|
||||
{ VOLD_CMD_MOUNT_VOLUME, do_mount_volume },
|
||||
{ VOLD_CMD_EJECT_MEDIA, do_eject_media },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int process_framework_command(int socket)
|
||||
{
|
||||
int rc;
|
||||
char buffer[101];
|
||||
|
||||
if ((rc = read(socket, buffer, sizeof(buffer) -1)) < 0) {
|
||||
LOGE("Unable to read framework command (%s)\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int i;
|
||||
|
||||
buffer[rc] = 0;
|
||||
|
||||
for (i = 0; i < rc; i++) {
|
||||
if (buffer[i] == 0) {
|
||||
dispatch_cmd(buffer + start);
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dispatch_cmd(char *cmd)
|
||||
{
|
||||
struct cmd_dispatch *c;
|
||||
|
||||
LOG_VOL("dispatch_cmd(%s):\n", cmd);
|
||||
|
||||
for (c = dispatch_table; c->cmd != NULL; c++) {
|
||||
if (!strncmp(c->cmd, cmd, strlen(c->cmd))) {
|
||||
c->dispatch(cmd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOGE("No cmd handlers defined for '%s'\n", cmd);
|
||||
}
|
||||
|
||||
static int do_send_ums_status(char *cmd)
|
||||
{
|
||||
return ums_send_status();
|
||||
}
|
||||
|
||||
static int do_set_ums_enable(char *cmd)
|
||||
{
|
||||
if (!strcmp(cmd, VOLD_CMD_ENABLE_UMS))
|
||||
return volmgr_enable_ums(true);
|
||||
|
||||
return volmgr_enable_ums(false);
|
||||
}
|
||||
|
||||
static int do_mount_volume(char *cmd)
|
||||
{
|
||||
return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]);
|
||||
}
|
||||
|
||||
static int do_eject_media(char *cmd)
|
||||
{
|
||||
return volmgr_stop_volume_by_mountpoint(&cmd[strlen("eject_media:")]);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _CMD_DISPATCH_H
|
||||
#define _CMD_DISPATCH_H
|
||||
|
||||
// These must match the strings in java/android/android/os/UsbListener.java
|
||||
#define VOLD_CMD_ENABLE_UMS "enable_ums"
|
||||
#define VOLD_CMD_DISABLE_UMS "disable_ums"
|
||||
#define VOLD_CMD_SEND_UMS_STATUS "send_ums_status"
|
||||
|
||||
// these commands should contain a volume mount point after the colon
|
||||
#define VOLD_CMD_MOUNT_VOLUME "mount_volume:"
|
||||
#define VOLD_CMD_EJECT_MEDIA "eject_media:"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
/*-
|
||||
* Copyright (c) 1987, 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)disklabel.h 8.2 (Berkeley) 7/10/94
|
||||
* $FreeBSD: src/sys/sys/diskmbr.h,v 1.99.2.1 2005/01/31 23:26:56 imp Exp $
|
||||
*/
|
||||
|
||||
#ifndef _SYS_DISKMBR_H_
|
||||
#define _SYS_DISKMBR_H_
|
||||
|
||||
#define DOSBBSECTOR 0 /* DOS boot block relative sector number */
|
||||
#define DOSPARTOFF 446
|
||||
#define DOSPARTSIZE 16
|
||||
#define NDOSPART 4
|
||||
#define NEXTDOSPART 32
|
||||
#define DOSMAGICOFFSET 510
|
||||
#define DOSMAGIC 0xAA55
|
||||
|
||||
#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */
|
||||
#define DOSPTYP_LINSWP 0x82 /* Linux swap partition */
|
||||
#define DOSPTYP_LINUX 0x83 /* Linux partition */
|
||||
#define DOSPTYP_PMBR 0xee /* GPT Protective MBR */
|
||||
#define DOSPTYP_EXT 5 /* DOS extended partition */
|
||||
#define DOSPTYP_EXTLBA 15 /* DOS extended partition */
|
||||
|
||||
struct dos_partition {
|
||||
unsigned char dp_flag; /* bootstrap flags */
|
||||
unsigned char dp_shd; /* starting head */
|
||||
unsigned char dp_ssect; /* starting sector */
|
||||
unsigned char dp_scyl; /* starting cylinder */
|
||||
unsigned char dp_typ; /* partition type */
|
||||
unsigned char dp_ehd; /* end head */
|
||||
unsigned char dp_esect; /* end sector */
|
||||
unsigned char dp_ecyl; /* end cylinder */
|
||||
u_int32_t dp_start; /* absolute starting sector number */
|
||||
u_int32_t dp_size; /* partition size in sectors */
|
||||
};
|
||||
#ifdef CTASSERT
|
||||
CTASSERT(sizeof (struct dos_partition) == DOSPARTSIZE);
|
||||
#endif
|
||||
|
||||
void dos_partition_dec(void const *pp, struct dos_partition *d);
|
||||
void dos_partition_enc(void *pp, struct dos_partition *d);
|
||||
|
||||
#define DPSECT(s) ((s) & 0x3f) /* isolate relevant bits of sector */
|
||||
#define DPCYL(c, s) ((c) + (((s) & 0xc0)<<2)) /* and those that are cylinder */
|
||||
|
||||
#define DIOCSMBR _IOW('M', 129, u_char[512])
|
||||
|
||||
#endif /* !_SYS_DISKMBR_H_ */
|
|
@ -0,0 +1,62 @@
|
|||
/*-
|
||||
* Copyright (c) 2003 Poul-Henning Kamp
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Functions to encode or decode struct dos_partition into a bytestream
|
||||
* of correct endianess and packing. These functions do no validation
|
||||
* or sanity checking, they only pack/unpack the fields correctly.
|
||||
*
|
||||
* NB! This file must be usable both in kernel and userland.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include "diskmbr.h"
|
||||
|
||||
static __inline uint32_t __unused
|
||||
le32dec(const void *buf)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)buf;
|
||||
|
||||
return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
void
|
||||
dos_partition_dec(void const *pp, struct dos_partition *d)
|
||||
{
|
||||
unsigned char const *p = pp;
|
||||
|
||||
d->dp_flag = p[0];
|
||||
d->dp_shd = p[1];
|
||||
d->dp_ssect = p[2];
|
||||
d->dp_scyl = p[3];
|
||||
d->dp_typ = p[4];
|
||||
d->dp_ehd = p[5];
|
||||
d->dp_esect = p[6];
|
||||
d->dp_ecyl = p[7];
|
||||
d->dp_start = le32dec(p + 8);
|
||||
d->dp_size = le32dec(p + 12);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INOTIFY_EVT_H
|
||||
#define _INOTIFY_EVT_H
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "private/android_filesystem_config.h"
|
||||
#include "cutils/log.h"
|
||||
|
||||
int parent(const char *tag, int parent_read) {
|
||||
int status;
|
||||
char buffer[4096];
|
||||
|
||||
int a = 0; // start index of unprocessed data
|
||||
int b = 0; // end index of unprocessed data
|
||||
int sz;
|
||||
while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
|
||||
|
||||
sz += b;
|
||||
// Log one line at a time
|
||||
for (b = 0; b < sz; b++) {
|
||||
if (buffer[b] == '\r') {
|
||||
buffer[b] = '\0';
|
||||
} else if (buffer[b] == '\n') {
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
a = b + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (a == 0 && b == sizeof(buffer) - 1) {
|
||||
// buffer is full, flush
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
b = 0;
|
||||
} else if (a != b) {
|
||||
// Keep left-overs
|
||||
b -= a;
|
||||
memmove(buffer, &buffer[a], b);
|
||||
a = 0;
|
||||
} else {
|
||||
a = 0;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
}
|
||||
// Flush remaining data
|
||||
if (a != b) {
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
}
|
||||
status = 0xAAAA;
|
||||
if (wait(&status) != -1) { // Wait for child
|
||||
if (WIFEXITED(status)) {
|
||||
LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
|
||||
WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status))
|
||||
LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
|
||||
WTERMSIG(status));
|
||||
else if (WIFSTOPPED(status))
|
||||
LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
|
||||
WSTOPSIG(status));
|
||||
} else
|
||||
LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
|
||||
strerror(errno), errno);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
void child(int argc, char* argv[]) {
|
||||
// create null terminated argv_child array
|
||||
char* argv_child[argc + 1];
|
||||
memcpy(argv_child, argv, argc * sizeof(char *));
|
||||
argv_child[argc] = NULL;
|
||||
|
||||
// XXX: PROTECT FROM VIKING KILLER
|
||||
if (execvp(argv_child[0], argv_child)) {
|
||||
LOG(LOG_ERROR, "logwrapper",
|
||||
"executing %s failed: %s\n", argv_child[0], strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int logwrap(int argc, char* argv[], pid_t *childPid)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
int parent_ptty;
|
||||
int child_ptty;
|
||||
char *child_devname = NULL;
|
||||
|
||||
/* Use ptty instead of socketpair so that STDOUT is not buffered */
|
||||
parent_ptty = open("/dev/ptmx", O_RDWR);
|
||||
if (parent_ptty < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
|
||||
((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Failed to fork\n");
|
||||
return -errno;
|
||||
} else if (pid == 0) {
|
||||
child_ptty = open(child_devname, O_RDWR);
|
||||
if (child_ptty < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Problem with child ptty\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// redirect stdout and stderr
|
||||
close(parent_ptty);
|
||||
dup2(child_ptty, 1);
|
||||
dup2(child_ptty, 2);
|
||||
close(child_ptty);
|
||||
|
||||
child(argc, argv);
|
||||
} else {
|
||||
return parent(argv[0], parent_ptty);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LOGWRAPPER_H
|
||||
#define _LOGWRAPPER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
int logwrap(int argc, char* argv[]);
|
||||
#endif
|
|
@ -0,0 +1,165 @@
|
|||
|
||||
/*
|
||||
* 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 <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "media.h"
|
||||
|
||||
static media_list_t *list_root = NULL;
|
||||
|
||||
media_t *media_create(char *devpath, char *name, char *serial, media_type_t type)
|
||||
{
|
||||
media_list_t *list_entry;
|
||||
media_t *new;
|
||||
|
||||
if (!(new = malloc(sizeof(media_t))))
|
||||
return NULL;
|
||||
|
||||
memset(new, 0, sizeof(media_t));
|
||||
|
||||
if (!(list_entry = malloc(sizeof(media_list_t)))) {
|
||||
free(new);
|
||||
return NULL;
|
||||
}
|
||||
list_entry->media = new;
|
||||
list_entry->next = NULL;
|
||||
|
||||
if (!list_root)
|
||||
list_root = list_entry;
|
||||
else {
|
||||
media_list_t *list_scan = list_root;
|
||||
while(list_scan->next)
|
||||
list_scan = list_scan->next;
|
||||
list_scan->next = list_entry;
|
||||
}
|
||||
|
||||
new->devpath = strdup(devpath);
|
||||
new->name = strdup(name);
|
||||
if (!serial)
|
||||
new->serial = 0;
|
||||
else
|
||||
new->serial = strtoul(serial, NULL, 0);
|
||||
|
||||
new->media_type = type;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void media_destroy(media_t *media)
|
||||
{
|
||||
media_list_t *list_next;
|
||||
|
||||
if (list_root->media == media) {
|
||||
list_next = list_root->next;
|
||||
free(list_root);
|
||||
list_root = list_next;
|
||||
} else {
|
||||
media_list_t *list_scan = list_root;
|
||||
while (list_scan->next->media != media)
|
||||
list_scan = list_scan -> next;
|
||||
list_next = list_scan->next->next;
|
||||
free(list_scan->next);
|
||||
list_scan->next = list_next;
|
||||
}
|
||||
|
||||
free(media->devpath);
|
||||
free(media->name);
|
||||
|
||||
if (media->devs)
|
||||
LOGE("media_destroy(): media still has blkdevs associated with it! Possible leak\n");
|
||||
free(media);
|
||||
}
|
||||
|
||||
media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match)
|
||||
{
|
||||
media_list_t *list_scan = list_root;
|
||||
|
||||
while (list_scan) {
|
||||
if (fuzzy_match) {
|
||||
if (!strncmp(list_scan->media->devpath, devpath, strlen(devpath)))
|
||||
return list_scan->media;
|
||||
} else {
|
||||
if (!strcmp(list_scan->media->devpath, devpath))
|
||||
return list_scan->media;
|
||||
}
|
||||
list_scan = list_scan->next;
|
||||
}
|
||||
#if DEBUG_MEDIA
|
||||
LOG_VOL("media_lookup_by_path(): No media found @ %s\n", devpath);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int media_add_blkdev(media_t *card, blkdev_t *dev)
|
||||
{
|
||||
blkdev_list_t *list_entry;
|
||||
|
||||
if (!(list_entry = malloc(sizeof(blkdev_list_t)))) {
|
||||
LOGE("Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
list_entry->next = NULL;
|
||||
list_entry->dev = dev;
|
||||
if (!card->devs)
|
||||
card->devs = list_entry;
|
||||
else {
|
||||
blkdev_list_t *scan = card->devs;
|
||||
|
||||
while(scan->next)
|
||||
scan = scan->next;
|
||||
|
||||
scan->next = list_entry;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void media_remove_blkdev(media_t *card, blkdev_t *dev)
|
||||
{
|
||||
if (card->devs->dev == dev)
|
||||
card->devs = card->devs->next;
|
||||
else {
|
||||
blkdev_list_t *scan = card->devs;
|
||||
while (scan->next->dev != dev)
|
||||
scan = scan -> next;
|
||||
blkdev_list_t *next = scan->next->next;
|
||||
free(scan->next);
|
||||
scan->next = next;
|
||||
}
|
||||
}
|
||||
|
||||
media_t *media_lookup_by_dev(blkdev_t *dev)
|
||||
{
|
||||
media_list_t *media_scan = list_root;
|
||||
|
||||
while (media_scan) {
|
||||
blkdev_list_t *blk_scan = media_scan->media->devs;
|
||||
while (blk_scan) {
|
||||
if (blk_scan->dev == dev)
|
||||
return media_scan->media;
|
||||
blk_scan = blk_scan->next;
|
||||
}
|
||||
media_scan = media_scan->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MEDIA_H
|
||||
#define _MEDIA_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "blkdev.h"
|
||||
|
||||
typedef enum media_type {
|
||||
media_unknown,
|
||||
media_mmc,
|
||||
media_dm
|
||||
} media_type_t;
|
||||
|
||||
typedef struct media {
|
||||
char *devpath;
|
||||
char *name;
|
||||
uint32_t serial;
|
||||
media_type_t media_type;
|
||||
|
||||
blkdev_list_t *devs;
|
||||
} media_t;
|
||||
|
||||
typedef struct media_list {
|
||||
media_t *media;
|
||||
struct media_list *next;
|
||||
} media_list_t;
|
||||
|
||||
media_t *media_create(char *devpath, char *name, char *serial, enum media_type);
|
||||
media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match);
|
||||
media_t *media_lookup_by_dev(blkdev_t *dev);
|
||||
void media_destroy(media_t *media);
|
||||
int media_add_blkdev(media_t *media, blkdev_t *dev);
|
||||
void media_remove_blkdev(media_t *media, blkdev_t *dev);
|
||||
#endif
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *read_file(char *filename, ssize_t *_size)
|
||||
{
|
||||
int ret, fd;
|
||||
struct stat sb;
|
||||
ssize_t size;
|
||||
void *buffer = NULL;
|
||||
|
||||
/* open the file */
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
/* find out how big it is */
|
||||
if (fstat(fd, &sb) < 0)
|
||||
goto bail;
|
||||
size = sb.st_size;
|
||||
|
||||
/* allocate memory for it to be read into */
|
||||
buffer = malloc(size);
|
||||
if (!buffer)
|
||||
goto bail;
|
||||
|
||||
/* slurp it into our buffer */
|
||||
ret = read(fd, buffer, size);
|
||||
if (ret != size)
|
||||
goto bail;
|
||||
|
||||
/* let the caller know how big it is */
|
||||
*_size = size;
|
||||
|
||||
bail:
|
||||
close(fd);
|
||||
return buffer;
|
||||
}
|
||||
char *truncate_sysfs_path(char *path, int num_elements_to_remove, char *buffer)
|
||||
{
|
||||
int i;
|
||||
|
||||
strcpy(buffer, path);
|
||||
|
||||
for (i = 0; i < num_elements_to_remove; i++) {
|
||||
char *p = &buffer[strlen(buffer)-1];
|
||||
|
||||
for (p = &buffer[strlen(buffer) -1]; *p != '/'; p--);
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var)
|
||||
{
|
||||
char filename[255];
|
||||
char *p;
|
||||
ssize_t sz;
|
||||
|
||||
sprintf(filename, "/sys%s/%s", devpath, var);
|
||||
p = read_file(filename, &sz);
|
||||
p[(strlen(p) - 1)] = '\0';
|
||||
strncpy(buffer, p, maxlen);
|
||||
free(p);
|
||||
return buffer;
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
|
||||
/*
|
||||
* 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 <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "mmc.h"
|
||||
#include "media.h"
|
||||
|
||||
#define DEBUG_BOOTSTRAP 0
|
||||
|
||||
static int mmc_bootstrap_controller(char *sysfs_path);
|
||||
static int mmc_bootstrap_card(char *sysfs_path);
|
||||
static int mmc_bootstrap_block(char *devpath);
|
||||
static int mmc_bootstrap_mmcblk(char *devpath);
|
||||
static int mmc_bootstrap_mmcblk_partition(char *devpath);
|
||||
|
||||
/*
|
||||
* Bootstrap our mmc information.
|
||||
*/
|
||||
int mmc_bootstrap()
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) {
|
||||
LOG_ERROR("Unable to open '%s' (%m)\n", SYSFS_CLASS_MMC_PATH);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
char tmp[255];
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name);
|
||||
if (mmc_bootstrap_controller(tmp))
|
||||
LOG_ERROR("Error bootstrapping controller '%s' (%m)\n", tmp);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_bootstrap_controller(char *sysfs_path)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
#if DEBUG_BOOTSTRAP
|
||||
LOG_VOL("bootstrap_controller(%s):\n", sysfs_path);
|
||||
#endif
|
||||
if (!(d = opendir(sysfs_path))) {
|
||||
LOG_ERROR("Unable to open '%s' (%m)\n", sysfs_path);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
char tmp[255];
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if ((!strcmp(de->d_name, "uevent")) ||
|
||||
(!strcmp(de->d_name, "subsystem")) ||
|
||||
(!strcmp(de->d_name, "device")) ||
|
||||
(!strcmp(de->d_name, "power"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf(tmp, "%s/%s", sysfs_path, de->d_name);
|
||||
|
||||
if (mmc_bootstrap_card(tmp) < 0)
|
||||
LOG_ERROR("Error bootstrapping card '%s' (%m)\n", tmp);
|
||||
} // while
|
||||
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_bootstrap_card(char *sysfs_path)
|
||||
{
|
||||
char saved_cwd[255];
|
||||
char new_cwd[255];
|
||||
char *devpath;
|
||||
char *uevent_params[4];
|
||||
char *p;
|
||||
char filename[255];
|
||||
char tmp[255];
|
||||
ssize_t sz;
|
||||
|
||||
#if DEBUG_BOOTSTRAP
|
||||
LOG_VOL("bootstrap_card(%s):\n", sysfs_path);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* sysfs_path is based on /sys/class, but we want the actual device class
|
||||
*/
|
||||
if (!getcwd(saved_cwd, sizeof(saved_cwd))) {
|
||||
LOGE("Buffer too small for working dir path\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (chdir(sysfs_path) < 0) {
|
||||
LOGE("Unable to chdir to %s (%m)\n", sysfs_path);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!getcwd(new_cwd, sizeof(new_cwd))) {
|
||||
LOGE("Buffer too small for device path\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (chdir(saved_cwd) < 0) {
|
||||
LOGE("Unable to restore working dir\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
devpath = &new_cwd[4]; // Skip over '/sys'
|
||||
|
||||
/*
|
||||
* Collect parameters so we can simulate a UEVENT
|
||||
*/
|
||||
sprintf(tmp, "DEVPATH=%s", devpath);
|
||||
uevent_params[0] = (char *) strdup(tmp);
|
||||
|
||||
sprintf(filename, "/sys%s/type", devpath);
|
||||
p = read_file(filename, &sz);
|
||||
p[strlen(p) - 1] = '\0';
|
||||
sprintf(tmp, "MMC_TYPE=%s", p);
|
||||
free(p);
|
||||
uevent_params[1] = (char *) strdup(tmp);
|
||||
|
||||
sprintf(filename, "/sys%s/name", devpath);
|
||||
p = read_file(filename, &sz);
|
||||
p[strlen(p) - 1] = '\0';
|
||||
sprintf(tmp, "MMC_NAME=%s", p);
|
||||
free(p);
|
||||
uevent_params[2] = (char *) strdup(tmp);
|
||||
|
||||
uevent_params[3] = (char *) NULL;
|
||||
|
||||
if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) {
|
||||
LOGE("Error simulating uevent (%m)\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for block drivers
|
||||
*/
|
||||
char block_devpath[255];
|
||||
sprintf(tmp, "%s/block", devpath);
|
||||
sprintf(filename, "/sys%s/block", devpath);
|
||||
if (!access(filename, F_OK)) {
|
||||
if (mmc_bootstrap_block(tmp)) {
|
||||
LOGE("Error bootstrapping block @ %s\n", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_bootstrap_block(char *devpath)
|
||||
{
|
||||
char blockdir_path[255];
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
#if DEBUG_BOOTSTRAP
|
||||
LOG_VOL("mmc_bootstrap_block(%s):\n", devpath);
|
||||
#endif
|
||||
|
||||
sprintf(blockdir_path, "/sys%s", devpath);
|
||||
|
||||
if (!(d = opendir(blockdir_path))) {
|
||||
LOGE("Failed to opendir %s\n", devpath);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
char tmp[255];
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
sprintf(tmp, "%s/%s", devpath, de->d_name);
|
||||
if (mmc_bootstrap_mmcblk(tmp))
|
||||
LOGE("Error bootstraping mmcblk @ %s\n", tmp);
|
||||
}
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_bootstrap_mmcblk(char *devpath)
|
||||
{
|
||||
char *mmcblk_devname;
|
||||
int part_no;
|
||||
int rc;
|
||||
|
||||
#if DEBUG_BOOTSTRAP
|
||||
LOG_VOL("mmc_bootstrap_mmcblk(%s):\n", devpath);
|
||||
#endif
|
||||
|
||||
if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) {
|
||||
LOGE("Error bootstrapping mmcblk partition '%s'\n", devpath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (mmcblk_devname = &devpath[strlen(devpath)];
|
||||
*mmcblk_devname != '/'; mmcblk_devname--);
|
||||
mmcblk_devname++;
|
||||
|
||||
for (part_no = 0; part_no < 4; part_no++) {
|
||||
char part_file[255];
|
||||
sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
|
||||
if (!access(part_file, F_OK)) {
|
||||
char part_devpath[255];
|
||||
|
||||
sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no);
|
||||
if (mmc_bootstrap_mmcblk_partition(part_devpath))
|
||||
LOGE("Error bootstrapping mmcblk partition '%s'\n", part_devpath);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_bootstrap_mmcblk_partition(char *devpath)
|
||||
{
|
||||
char filename[255];
|
||||
char *uevent_buffer;
|
||||
ssize_t sz;
|
||||
char *uevent_params[4];
|
||||
char tmp[255];
|
||||
FILE *fp;
|
||||
char line[255];
|
||||
|
||||
#if DEBUG_BOOTSTRAP
|
||||
LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):\n", devpath);
|
||||
#endif
|
||||
|
||||
sprintf(tmp, "DEVPATH=%s", devpath);
|
||||
uevent_params[0] = strdup(tmp);
|
||||
|
||||
sprintf(filename, "/sys%s/uevent", devpath);
|
||||
if (!(fp = fopen(filename, "r"))) {
|
||||
LOGE("Unable to open '%s' (%m)\n", filename);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
line[strlen(line)-1] = 0;
|
||||
if (!strncmp(line, "DEVTYPE=", 8))
|
||||
uevent_params[1] = strdup(line);
|
||||
else if (!strncmp(line, "MAJOR=",6))
|
||||
uevent_params[2] = strdup(line);
|
||||
else if (!strncmp(line, "MINOR=",6))
|
||||
uevent_params[3] = strdup(line);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) {
|
||||
LOGE("mmcblk uevent missing required params\n");
|
||||
return -1;
|
||||
}
|
||||
uevent_params[4] = '\0';
|
||||
|
||||
if (simulate_uevent("block", devpath, "add", uevent_params) < 0) {
|
||||
LOGE("Error simulating uevent (%m)\n");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MMC_H
|
||||
#define _MMC_H
|
||||
|
||||
#define SYSFS_CLASS_MMC_PATH "/sys/class/mmc_host"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,431 @@
|
|||
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "uevent.h"
|
||||
#include "mmc.h"
|
||||
#include "blkdev.h"
|
||||
#include "volmgr.h"
|
||||
#include "media.h"
|
||||
|
||||
#define DEBUG_UEVENT 0
|
||||
|
||||
#define UEVENT_PARAMS_MAX 32
|
||||
|
||||
enum uevent_action { action_add, action_remove, action_change };
|
||||
|
||||
struct uevent {
|
||||
char *path;
|
||||
enum uevent_action action;
|
||||
char *subsystem;
|
||||
char *param[UEVENT_PARAMS_MAX];
|
||||
unsigned int seqnum;
|
||||
};
|
||||
|
||||
struct uevent_dispatch {
|
||||
char *subsystem;
|
||||
int (* dispatch) (struct uevent *);
|
||||
};
|
||||
|
||||
static void dump_uevent(struct uevent *);
|
||||
static int dispatch_uevent(struct uevent *event);
|
||||
static void free_uevent(struct uevent *event);
|
||||
static char *get_uevent_param(struct uevent *event, char *param_name);
|
||||
|
||||
static int handle_powersupply_event(struct uevent *event);
|
||||
static int handle_switch_event(struct uevent *);
|
||||
static int handle_battery_event(struct uevent *);
|
||||
static int handle_mmc_event(struct uevent *);
|
||||
static int handle_block_event(struct uevent *);
|
||||
static int handle_bdi_event(struct uevent *);
|
||||
static void _cb_blkdev_ok_to_destroy(blkdev_t *dev);
|
||||
|
||||
static struct uevent_dispatch dispatch_table[] = {
|
||||
{ "switch", handle_switch_event },
|
||||
{ "battery", handle_battery_event },
|
||||
{ "mmc", handle_mmc_event },
|
||||
{ "block", handle_block_event },
|
||||
{ "bdi", handle_bdi_event },
|
||||
{ "power_supply", handle_powersupply_event },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int process_uevent_message(int socket)
|
||||
{
|
||||
char buffer[64 * 1024]; // Thank god we're not in the kernel :)
|
||||
int count;
|
||||
char *s = buffer;
|
||||
char *end;
|
||||
struct uevent *event;
|
||||
int param_idx = 0;
|
||||
int i;
|
||||
int first = 1;
|
||||
int rc = 0;
|
||||
|
||||
if ((count = recv(socket, buffer, sizeof(buffer), 0)) < 0) {
|
||||
LOGE("Error receiving uevent (%s)\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!(event = malloc(sizeof(struct uevent)))) {
|
||||
LOGE("Error allocating memory (%s)\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(event, 0, sizeof(struct uevent));
|
||||
|
||||
end = s + count;
|
||||
while (s < end) {
|
||||
if (first) {
|
||||
char *p;
|
||||
for (p = s; *p != '@'; p++);
|
||||
p++;
|
||||
event->path = strdup(p);
|
||||
first = 0;
|
||||
} else {
|
||||
if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
|
||||
char *a = s + strlen("ACTION=");
|
||||
|
||||
if (!strcmp(a, "add"))
|
||||
event->action = action_add;
|
||||
else if (!strcmp(a, "change"))
|
||||
event->action = action_change;
|
||||
else if (!strcmp(a, "remove"))
|
||||
event->action = action_remove;
|
||||
} else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
|
||||
event->seqnum = atoi(s + strlen("SEQNUM="));
|
||||
else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
|
||||
event->subsystem = strdup(s + strlen("SUBSYSTEM="));
|
||||
else
|
||||
event->param[param_idx++] = strdup(s);
|
||||
}
|
||||
s+= (strlen(s) + 1);
|
||||
}
|
||||
|
||||
rc = dispatch_uevent(event);
|
||||
|
||||
free_uevent(event);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int simulate_uevent(char *subsys, char *path, char *action, char **params)
|
||||
{
|
||||
struct uevent *event;
|
||||
char tmp[255];
|
||||
int i, rc;
|
||||
|
||||
if (!(event = malloc(sizeof(struct uevent)))) {
|
||||
LOGE("Error allocating memory (%s)\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(event, 0, sizeof(struct uevent));
|
||||
|
||||
event->subsystem = strdup(subsys);
|
||||
|
||||
if (!strcmp(action, "add"))
|
||||
event->action = action_add;
|
||||
else if (!strcmp(action, "change"))
|
||||
event->action = action_change;
|
||||
else if (!strcmp(action, "remove"))
|
||||
event->action = action_remove;
|
||||
else {
|
||||
LOGE("Invalid action '%s'\n", action);
|
||||
return -1;
|
||||
}
|
||||
|
||||
event->path = strdup(path);
|
||||
|
||||
for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
|
||||
if (!params[i])
|
||||
break;
|
||||
event->param[i] = strdup(params[i]);
|
||||
}
|
||||
|
||||
rc = dispatch_uevent(event);
|
||||
free_uevent(event);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dispatch_uevent(struct uevent *event)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; dispatch_table[i].subsystem != NULL; i++) {
|
||||
if (!strcmp(dispatch_table[i].subsystem, event->subsystem))
|
||||
return dispatch_table[i].dispatch(event);
|
||||
}
|
||||
|
||||
#if DEBUG_UEVENT
|
||||
LOG_VOL("No uevent handlers registered for '%s' subsystem\n", event->subsystem);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_uevent(struct uevent *event)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s\n",
|
||||
event->seqnum, event->subsystem, event->action, event->path);
|
||||
for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
|
||||
if (!event->param[i])
|
||||
break;
|
||||
LOG_VOL("%s\n", event->param[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_uevent(struct uevent *event)
|
||||
{
|
||||
int i;
|
||||
free(event->path);
|
||||
free(event->subsystem);
|
||||
for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
|
||||
if (!event->param[i])
|
||||
break;
|
||||
free(event->param[i]);
|
||||
}
|
||||
free(event);
|
||||
}
|
||||
|
||||
static char *get_uevent_param(struct uevent *event, char *param_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
|
||||
if (!event->param[i])
|
||||
break;
|
||||
if (!strncmp(event->param[i], param_name, strlen(param_name)))
|
||||
return &event->param[i][strlen(param_name) + 1];
|
||||
}
|
||||
|
||||
LOGE("get_uevent_param(): No parameter '%s' found\n", param_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ---------------
|
||||
* Uevent Handlers
|
||||
* ---------------
|
||||
*/
|
||||
|
||||
static int handle_powersupply_event(struct uevent *event)
|
||||
{
|
||||
dump_uevent(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_switch_event(struct uevent *event)
|
||||
{
|
||||
char *name = get_uevent_param(event, "SWITCH_NAME");
|
||||
char *state = get_uevent_param(event, "SWITCH_STATE");
|
||||
|
||||
if (!strcmp(name, "usb_mass_storage")) {
|
||||
if (!strcmp(state, "online")) {
|
||||
ums_hostconnected_set(true);
|
||||
} else {
|
||||
ums_hostconnected_set(false);
|
||||
}
|
||||
} else
|
||||
LOG_VOL("handle_switch_event(): Ignoring switch '%s'\n", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_battery_event(struct uevent *event)
|
||||
{
|
||||
dump_uevent(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_block_event(struct uevent *event)
|
||||
{
|
||||
char mediapath[255];
|
||||
media_t *media;
|
||||
int n;
|
||||
int maj, min;
|
||||
blkdev_t *blkdev;
|
||||
|
||||
/*
|
||||
* Look for backing media for this block device
|
||||
*/
|
||||
if (!strcmp(get_uevent_param(event, "DEVTYPE"), "disk"))
|
||||
n = 2;
|
||||
else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "partition"))
|
||||
n = 3;
|
||||
else {
|
||||
LOGE("Bad blockdev type '%s'\n", get_uevent_param(event, "DEVTYPE"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
truncate_sysfs_path(event->path, n, mediapath);
|
||||
|
||||
if (!(media = media_lookup_by_path(mediapath, false))) {
|
||||
#if DEBUG_UEVENT
|
||||
LOG_VOL("No backend media found @ device path '%s'\n", mediapath);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
maj = atoi(get_uevent_param(event, "MAJOR"));
|
||||
min = atoi(get_uevent_param(event, "MINOR"));
|
||||
|
||||
if (event->action == action_add) {
|
||||
blkdev_t *disk;
|
||||
boolean pending = false;
|
||||
|
||||
/*
|
||||
* If there isn't a disk already its because *we*
|
||||
* are the disk
|
||||
*/
|
||||
disk = blkdev_lookup_by_devno(maj, 0);
|
||||
|
||||
/*
|
||||
* It is possible that there is already a blkdev
|
||||
* for this device (created by blkdev_create_pending_partition())
|
||||
*/
|
||||
|
||||
if ((blkdev = blkdev_lookup_by_devno(maj, min))) {
|
||||
blkdev_devpath_set(blkdev, event->path);
|
||||
pending = true;
|
||||
} else {
|
||||
if (!(blkdev = blkdev_create(disk,
|
||||
event->path,
|
||||
maj,
|
||||
min,
|
||||
media,
|
||||
get_uevent_param(event, "DEVTYPE")))) {
|
||||
LOGE("Unable to allocate new blkdev (%m)\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the blkdev to media
|
||||
*/
|
||||
int rc;
|
||||
if ((rc = media_add_blkdev(media, blkdev)) < 0) {
|
||||
LOGE("Unable to add blkdev to card (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
LOG_VOL("New blkdev %d.%d on media %s, media path %s\n", blkdev->major, blkdev->minor, media->name, mediapath);
|
||||
|
||||
if (pending) {
|
||||
/*
|
||||
* This blkdev already has its dev_fspath set so
|
||||
* if all partitions are read, pass it off to
|
||||
* the volume manager
|
||||
*/
|
||||
LOG_VOL("Pending disk '%d.%d' has %d pending partitions\n",
|
||||
blkdev->disk->major, blkdev->disk->minor,
|
||||
blkdev_get_num_pending_partitions(blkdev->disk));
|
||||
|
||||
if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
|
||||
if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
|
||||
LOGE("Volmgr failed to handle pending device (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event->action == action_remove) {
|
||||
int rc;
|
||||
|
||||
if (!(blkdev = blkdev_lookup_by_devno(maj, min))) {
|
||||
#if DEBUG_UEVENT
|
||||
LOG_VOL("We aren't handling blkdev @ %s\n", event->path);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_VOL("Destroying blkdev %d.%d @ %s on media %s\n", blkdev->major, blkdev->minor, blkdev->devpath, media->name);
|
||||
if ((rc = volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy)) < 0)
|
||||
LOGE("Error notifying volmgr of eject\n");
|
||||
} else {
|
||||
#if DEBUG_UEVENT
|
||||
LOG_VOL("No handler implemented for action %d\n", event->action);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cb_blkdev_ok_to_destroy(blkdev_t *dev)
|
||||
{
|
||||
media_t *media = media_lookup_by_dev(dev);
|
||||
if (media)
|
||||
media_remove_blkdev(media, dev);
|
||||
blkdev_destroy(dev);
|
||||
}
|
||||
|
||||
static int handle_bdi_event(struct uevent *event)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_mmc_event(struct uevent *event)
|
||||
{
|
||||
if (event->action == action_add) {
|
||||
media_t *media;
|
||||
char serial[80];
|
||||
char *type;
|
||||
|
||||
/*
|
||||
* Pull card information from sysfs
|
||||
*/
|
||||
type = get_uevent_param(event, "MMC_TYPE");
|
||||
if (strcmp(type, "SD") && strcmp(type, "MMC"))
|
||||
return 0;
|
||||
|
||||
read_sysfs_var(serial, sizeof(serial), event->path, "serial");
|
||||
if (!(media = media_create(event->path,
|
||||
get_uevent_param(event, "MMC_NAME"),
|
||||
serial,
|
||||
media_mmc))) {
|
||||
LOGE("Unable to allocate new media (%m)\n");
|
||||
return -1;
|
||||
}
|
||||
LOG_VOL("New MMC card '%s' (serial %u) added @ %s\n", media->name,
|
||||
media->serial, media->devpath);
|
||||
} else if (event->action == action_remove) {
|
||||
media_t *media;
|
||||
|
||||
if (!(media = media_lookup_by_path(event->path, false))) {
|
||||
LOGE("Unable to lookup media '%s'\n", event->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_VOL("MMC card '%s' (serial %u) @ %s removed\n", media->name,
|
||||
media->serial, media->devpath);
|
||||
/*
|
||||
* If this media is still mounted, then we have an unsafe removal
|
||||
*/
|
||||
media_destroy(media);
|
||||
} else {
|
||||
#if DEBUG_UEVENT
|
||||
LOG_VOL("No handler implemented for action %d\n", event->action);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _UEVENT_MSG_H
|
||||
#define _UEVENT_MSG_H
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
/*
|
||||
* 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 <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "ums.h"
|
||||
|
||||
static boolean host_connected = false;
|
||||
static boolean ums_enabled = false;
|
||||
|
||||
int ums_bootstrap(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ums_enabled_set(boolean enabled)
|
||||
{
|
||||
ums_enabled = enabled;
|
||||
send_msg(enabled ? VOLD_EVT_UMS_ENABLED : VOLD_EVT_UMS_DISABLED);
|
||||
}
|
||||
|
||||
boolean ums_enabled_get()
|
||||
{
|
||||
return ums_enabled;
|
||||
}
|
||||
|
||||
void ums_hostconnected_set(boolean connected)
|
||||
{
|
||||
LOG_VOL("ums_hostconnected_set(%d):\n", connected);
|
||||
host_connected = connected;
|
||||
|
||||
if (!connected)
|
||||
ums_enabled_set(false);
|
||||
send_msg(connected ? VOLD_EVT_UMS_CONNECTED : VOLD_EVT_UMS_DISCONNECTED);
|
||||
}
|
||||
|
||||
int ums_enable(char *dev_fspath, char *lun_syspath)
|
||||
{
|
||||
LOG_VOL("ums_enable(%s, %s):\n", dev_fspath, lun_syspath);
|
||||
|
||||
int fd;
|
||||
char filename[255];
|
||||
|
||||
sprintf(filename, "/sys/%s/file", lun_syspath);
|
||||
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||
LOGE("Unable to open '%s' (%s)\n", filename, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (write(fd, dev_fspath, strlen(dev_fspath)) < 0) {
|
||||
LOGE("Unable to write to ums lunfile (%s)\n", strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ums_disable(char *lun_syspath)
|
||||
{
|
||||
LOG_VOL("ums_disable(%s):\n", lun_syspath);
|
||||
|
||||
int fd;
|
||||
char filename[255];
|
||||
|
||||
sprintf(filename, "/sys/%s/file", lun_syspath);
|
||||
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||
LOGE("Unable to open '%s' (%s)\n", filename, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
char ch = 0;
|
||||
|
||||
if (write(fd, &ch, 1) < 0) {
|
||||
LOGE("Unable to write to ums lunfile (%s)\n", strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean ums_hostconnected_get(void)
|
||||
{
|
||||
return host_connected;
|
||||
}
|
||||
|
||||
int ums_send_status(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
LOG_VOL("ums_send_status():\n");
|
||||
|
||||
rc = send_msg(ums_enabled_get() ? VOLD_EVT_UMS_ENABLED :
|
||||
VOLD_EVT_UMS_DISABLED);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = send_msg(ums_hostconnected_get() ? VOLD_EVT_UMS_CONNECTED :
|
||||
VOLD_EVT_UMS_DISCONNECTED);
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _UMS_H
|
||||
#define _UMS_H
|
||||
|
||||
// these must match the corresponding strings in java/android/android/os/UsbListener.java
|
||||
#define VOLD_EVT_UMS_ENABLED "ums_enabled"
|
||||
#define VOLD_EVT_UMS_DISABLED "ums_disabled"
|
||||
#define VOLD_EVT_UMS_CONNECTED "ums_connected"
|
||||
#define VOLD_EVT_UMS_DISCONNECTED "ums_disconnected"
|
||||
|
||||
|
||||
int ums_send_status(void);
|
||||
int ums_enable(char *device_file, char *lun_syspath);
|
||||
int ums_disable(char *lun_syspath);
|
||||
#endif
|
|
@ -0,0 +1,250 @@
|
|||
|
||||
/*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <cutils/config_utils.h>
|
||||
#include <cutils/cpu_info.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "volmgr.h"
|
||||
|
||||
|
||||
#define VOLD_SOCKET "vold"
|
||||
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
|
||||
static int ver_major = 2;
|
||||
static int ver_minor = 0;
|
||||
static pthread_mutex_t write_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int fw_sock = -1;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int door_sock = -1;
|
||||
int inotify_sock = -1;
|
||||
int uevent_sock = -1;
|
||||
struct sockaddr_nl nladdr;
|
||||
int uevent_sz = 64 * 1024;
|
||||
|
||||
LOG_VOL("Android Volume Daemon version %d.%d\n", ver_major, ver_minor);
|
||||
|
||||
/*
|
||||
* Create all the various sockets we'll need
|
||||
*/
|
||||
|
||||
// Socket to listen on for incomming framework connections
|
||||
if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) {
|
||||
LOGE("Obtaining file descriptor socket '%s' failed: %s\n",
|
||||
VOLD_SOCKET, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen(door_sock, 4) < 0) {
|
||||
LOGE("Unable to listen on fd '%d' for socket '%s': %s\n",
|
||||
door_sock, VOLD_SOCKET, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Socket to listen on for changes to /dev/block
|
||||
if ((inotify_sock = inotify_init()) < 0) {
|
||||
LOGE("Unable to initialize inotify interface (%s)\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fcntl(inotify_sock, F_SETFL, O_NONBLOCK | fcntl(inotify_sock, F_GETFL));
|
||||
|
||||
if (inotify_add_watch(inotify_sock, DEVPATH, IN_CREATE | IN_DELETE) < 0) {
|
||||
LOGE("Unable to add inotify watch (%s)\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Socket to listen on for uevent changes
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = getpid();
|
||||
nladdr.nl_groups = 0xffffffff;
|
||||
|
||||
if ((uevent_sock = socket(PF_NETLINK,
|
||||
SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
|
||||
LOGE("Unable to create uevent socket: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz,
|
||||
sizeof(uevent_sz)) < 0) {
|
||||
LOGE("Unable to set uevent socket options: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
|
||||
LOGE("Unable to bind uevent socket: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bootstrap
|
||||
*/
|
||||
|
||||
// SD Card system
|
||||
mmc_bootstrap();
|
||||
|
||||
// USB Mass Storage
|
||||
ums_bootstrap();
|
||||
|
||||
// Volume Manager
|
||||
volmgr_bootstrap();
|
||||
|
||||
// Block device system
|
||||
inotify_bootstrap();
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
*/
|
||||
|
||||
while(1) {
|
||||
fd_set read_fds;
|
||||
struct timeval to;
|
||||
int max = 0;
|
||||
int rc = 0;
|
||||
|
||||
to.tv_sec = (60 * 60);
|
||||
to.tv_usec = 0;
|
||||
|
||||
FD_SET(door_sock, &read_fds);
|
||||
if (door_sock > max)
|
||||
max = door_sock;
|
||||
FD_SET(inotify_sock, &read_fds);
|
||||
if (inotify_sock > max)
|
||||
max = inotify_sock;
|
||||
FD_SET(uevent_sock, &read_fds);
|
||||
if (uevent_sock > max)
|
||||
max = uevent_sock;
|
||||
|
||||
if (fw_sock != -1) {
|
||||
FD_SET(fw_sock, &read_fds);
|
||||
if (fw_sock > max)
|
||||
max = fw_sock;
|
||||
}
|
||||
|
||||
if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {
|
||||
LOGE("select() failed (%s)\n", strerror(errno));
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(door_sock, &read_fds)) {
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
|
||||
alen = sizeof(addr);
|
||||
|
||||
if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {
|
||||
LOGE("Unable to accept framework connection (%s)\n",
|
||||
strerror(errno));
|
||||
}
|
||||
LOG_VOL("Accepted connection from framework\n");
|
||||
if ((rc = volmgr_send_states()) < 0) {
|
||||
LOGE("Unable to send volmgr status to framework (%d)\n", rc);
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(fw_sock, &read_fds)) {
|
||||
if ((rc = process_framework_command(fw_sock)) < 0) {
|
||||
if (rc == -ECONNRESET) {
|
||||
LOGE("Framework disconnected\n");
|
||||
close(fw_sock);
|
||||
fw_sock = -1;
|
||||
} else {
|
||||
LOGE("Error processing framework command (%s)\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(inotify_sock, &read_fds)) {
|
||||
if ((rc = process_inotify_event(inotify_sock)) < 0) {
|
||||
LOGE("Error processing inotify msg (%s)\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(uevent_sock, &read_fds)) {
|
||||
if ((rc = process_uevent_message(uevent_sock)) < 0) {
|
||||
LOGE("Error processing uevent msg (%s)\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // while
|
||||
|
||||
}
|
||||
|
||||
int send_msg(char* message)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
pthread_mutex_lock(&write_mutex);
|
||||
|
||||
LOG_VOL("send_msg(%s):\n", message);
|
||||
|
||||
if (fw_sock >= 0)
|
||||
result = write(fw_sock, message, strlen(message) + 1);
|
||||
|
||||
pthread_mutex_unlock(&write_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int send_msg_with_data(char *message, char *data)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
|
||||
if (!buffer) {
|
||||
LOGE("alloca failed in send_msg_with_data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(buffer, message);
|
||||
strcat(buffer, data);
|
||||
return send_msg(buffer);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef VOLD_H__
|
||||
#define VOLD_H__
|
||||
|
||||
#define LOG_TAG "vold"
|
||||
#include "cutils/log.h"
|
||||
|
||||
typedef int boolean;
|
||||
enum {
|
||||
false = 0,
|
||||
true = 1
|
||||
};
|
||||
|
||||
#define DEVPATH "/dev/block/"
|
||||
#define DEVPATHLENGTH 11
|
||||
|
||||
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
||||
|
||||
// Set this for logging error messages
|
||||
#define ENABLE_LOG_ERROR
|
||||
|
||||
// set this to log vold events
|
||||
#define ENABLE_LOG_VOL
|
||||
|
||||
#ifdef ENABLE_LOG_ERROR
|
||||
#define LOG_ERROR(fmt, args...) \
|
||||
{ LOGE(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_ERROR(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_ERROR */
|
||||
|
||||
#ifdef ENABLE_LOG_VOL
|
||||
#define LOG_VOL(fmt, args...) \
|
||||
{ LOGD(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_VOL(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_VOL */
|
||||
|
||||
#ifdef ENABLE_LOG_SERVER
|
||||
#define LOG_SERVER(fmt, args...) \
|
||||
{ LOGD(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_SERVER(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_SERVER */
|
||||
|
||||
#ifdef ENABLE_LOG_ASEC
|
||||
#define LOG_ASEC(fmt, args...) \
|
||||
{ LOGD(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_ASEC(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_ASEC */
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
||||
int process_framework_command(int socket);
|
||||
|
||||
int process_inotify_event(int fd);
|
||||
int inotify_bootstrap(void);
|
||||
|
||||
int process_uevent_message(int socket);
|
||||
int simulate_uevent(char *subsystem, char *path, char *action, char **params);
|
||||
|
||||
int mmc_bootstrap(void);
|
||||
int ums_bootstrap(void);
|
||||
|
||||
int volmgr_bootstrap(void);
|
||||
|
||||
void *read_file(char *filename, ssize_t *_size);
|
||||
char *truncate_sysfs_path(char *path, int num_elements_to_remove, char *buffer);
|
||||
char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var);
|
||||
|
||||
void ums_hostconnected_set(boolean connected);
|
||||
boolean ums_hostconnected_get(void);
|
||||
|
||||
int send_msg(char *msg);
|
||||
int send_msg_with_data(char *msg, char *data);
|
||||
#endif
|
|
@ -0,0 +1,792 @@
|
|||
|
||||
/*
|
||||
* 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 <sched.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <cutils/config_utils.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "volmgr.h"
|
||||
#include "blkdev.h"
|
||||
#include "ums.h"
|
||||
|
||||
#include "volmgr_ext3.h"
|
||||
#include "volmgr_vfat.h"
|
||||
|
||||
#define DEBUG_VOLMGR 0
|
||||
|
||||
static volume_t *vol_root = NULL;
|
||||
|
||||
static struct volmgr_fstable_entry fs_table[] = {
|
||||
{ "ext3", ext3_identify, ext3_check, ext3_mount },
|
||||
{ "vfat", vfat_identify, vfat_check, vfat_mount },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
struct _volume_state_event_map {
|
||||
volume_state_t state;
|
||||
char *event;
|
||||
char *property_val;
|
||||
};
|
||||
|
||||
static struct _volume_state_event_map volume_state_strings[] = {
|
||||
{ volstate_unknown, "volstate_unknown:", "unknown" },
|
||||
{ volstate_nomedia, VOLD_EVT_NOMEDIA, VOLD_ES_PVAL_NOMEDIA },
|
||||
{ volstate_unmounted, VOLD_EVT_UNMOUNTED, VOLD_ES_PVAL_UNMOUNTED },
|
||||
{ volstate_checking, VOLD_EVT_CHECKING, VOLD_ES_PVAL_CHECKING },
|
||||
{ volstate_mounted, VOLD_EVT_MOUNTED, VOLD_ES_PVAL_MOUNTED },
|
||||
{ volstate_mounted_ro, VOLD_EVT_MOUNTED_RO, VOLD_ES_PVAL_MOUNTED_RO },
|
||||
{ volstate_badremoval, VOLD_EVT_BADREMOVAL, VOLD_ES_PVAL_BADREMOVAL },
|
||||
{ volstate_damaged, VOLD_EVT_DAMAGED, VOLD_ES_PVAL_DAMAGED },
|
||||
{ volstate_nofs, VOLD_EVT_NOFS, VOLD_ES_PVAL_NOFS },
|
||||
{ volstate_ums, VOLD_EVT_UMS, VOLD_ES_PVAL_UMS },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static int volmgr_readconfig(char *cfg_path);
|
||||
static int volmgr_config_volume(cnode *node);
|
||||
static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy);
|
||||
static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev);
|
||||
static int _volmgr_start(volume_t *vol, blkdev_t *dev);
|
||||
static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev);
|
||||
static void *volmgr_start_fs_thread(void *arg);
|
||||
static void volmgr_start_fs_thread_sighandler(int signo);
|
||||
static void volume_setstate(volume_t *vol, volume_state_t state);
|
||||
static char *conv_volstate_to_eventstr(volume_state_t state);
|
||||
static char *conv_volstate_to_propstr(volume_state_t state);
|
||||
static int volume_send_state(volume_t *vol);
|
||||
static void _cb_volstopped_for_ums_enable(volume_t *v);
|
||||
static int _volmgr_enable_ums(volume_t *);
|
||||
static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *));
|
||||
static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, int emit_statechange);
|
||||
static void _cb_volume_stopped_for_eject(volume_t *v, void *arg);
|
||||
static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg);
|
||||
static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev);
|
||||
static void volmgr_uncage_reaper(volume_t *vol);
|
||||
static void volmgr_reaper_thread_sighandler(int signo);
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
int volmgr_bootstrap(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {
|
||||
LOGE("Unable to process config\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int volmgr_send_states(void)
|
||||
{
|
||||
volume_t *vol_scan = vol_root;
|
||||
int rc;
|
||||
|
||||
while (vol_scan) {
|
||||
pthread_mutex_lock(&vol_scan->lock);
|
||||
if ((rc = volume_send_state(vol_scan)) < 0) {
|
||||
LOGE("Error sending state to framework (%d)\n", rc);
|
||||
}
|
||||
pthread_mutex_unlock(&vol_scan->lock);
|
||||
vol_scan = vol_scan->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a block device is ready to be
|
||||
* evaluated by the volume manager.
|
||||
*/
|
||||
int volmgr_consider_disk(blkdev_t *dev)
|
||||
{
|
||||
volume_t *vol;
|
||||
|
||||
if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true))) {
|
||||
LOG_VOL("volmgr ignoring '%s' - no matching volume found\n", dev->media->devpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&vol->lock);
|
||||
int rc = _volmgr_consider_disk_and_vol(vol, dev);
|
||||
pthread_mutex_unlock(&vol->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int volmgr_start_volume_by_mountpoint(char *mount_point)
|
||||
{
|
||||
volume_t *v = vol_root;
|
||||
|
||||
while(v) {
|
||||
if (!strcmp(v->mount_point, mount_point)) {
|
||||
pthread_mutex_lock(&v->lock);
|
||||
if (!v->dev) {
|
||||
LOGE("Cannot start volume '%s' (volume is not bound to a blkdev)\n", mount_point);
|
||||
pthread_mutex_unlock(&v->lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) {
|
||||
LOGE("volmgr failed to start volume '%s'\n", v->mount_point);
|
||||
}
|
||||
pthread_mutex_unlock(&v->lock);
|
||||
return 0;
|
||||
}
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int volmgr_stop_volume_by_mountpoint(char *mount_point)
|
||||
{
|
||||
volume_t *v = vol_root;
|
||||
|
||||
while(v) {
|
||||
if (!strcmp(v->mount_point, mount_point)) {
|
||||
pthread_mutex_lock(&v->lock);
|
||||
if (volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable) < 0)
|
||||
LOGE("unable to shutdown volume '%s'\n", v->mount_point);
|
||||
pthread_mutex_unlock(&v->lock);
|
||||
return 0;
|
||||
}
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *))
|
||||
{
|
||||
#if DEBUG_VOLMGR
|
||||
LOG_VOL("volmgr_notify_eject(%s)\n", dev->dev_fspath);
|
||||
#endif
|
||||
|
||||
volume_t *v;
|
||||
|
||||
// XXX: Partitioning support is going to need us to stop *all*
|
||||
// devices in this volume
|
||||
if (!(v = volmgr_lookup_volume_by_dev(dev))) {
|
||||
if (cb)
|
||||
cb(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&v->lock);
|
||||
if (v->state == volstate_mounted)
|
||||
volume_setstate(v, volstate_badremoval);
|
||||
|
||||
int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
|
||||
|
||||
pthread_mutex_unlock(&v->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void _cb_volume_stopped_for_eject(volume_t *v, void *arg)
|
||||
{
|
||||
void (* eject_cb) (blkdev_t *) = arg;
|
||||
LOG_VOL("Volume %s has been stopped for eject\n", v->mount_point);
|
||||
|
||||
eject_cb(v->dev);
|
||||
v->dev = NULL; // Clear dev because its being ejected
|
||||
}
|
||||
|
||||
/*
|
||||
* Instructs the volume manager to enable or disable USB mass storage
|
||||
* on any volumes configured to use it.
|
||||
*/
|
||||
int volmgr_enable_ums(boolean enable)
|
||||
{
|
||||
volume_t *v = vol_root;
|
||||
|
||||
while(v) {
|
||||
if (v->ums_path) {
|
||||
int rc;
|
||||
|
||||
pthread_mutex_lock(&v->lock);
|
||||
if (enable) {
|
||||
// Stop the volume, and enable UMS in the callback
|
||||
if ((rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable)) < 0)
|
||||
LOGE("unable to shutdown volume '%s'\n", v->mount_point);
|
||||
} else {
|
||||
// Disable UMS
|
||||
if ((rc = ums_disable(v->ums_path)) < 0) {
|
||||
LOGE("unable to disable ums on '%s'\n", v->mount_point);
|
||||
pthread_mutex_unlock(&v->lock);
|
||||
continue;
|
||||
}
|
||||
volume_setstate(v, volstate_unmounted);
|
||||
|
||||
LOG_VOL("Kick-starting volume '%s' after UMS disable\n", v->dev->disk->dev_fspath);
|
||||
// Start volume
|
||||
if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) {
|
||||
LOGE("volmgr failed to consider disk '%s'\n", v->dev->disk->dev_fspath);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&v->lock);
|
||||
}
|
||||
v = v->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Static functions
|
||||
*/
|
||||
|
||||
// vol->lock must be held!
|
||||
static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#if DEBUG_VOLMGR
|
||||
LOG_VOL("volmgr_consider_disk_and_vol(%s, %s):\n", vol->mount_point, dev->dev_fspath);
|
||||
#endif
|
||||
|
||||
if (vol->state != volstate_nomedia && vol->state != volstate_unmounted) {
|
||||
LOGE("Volume manager is already handling volume '%s' (currently in state %d)\n", vol->mount_point, vol->state);
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
|
||||
volume_setstate(vol, volstate_unmounted);
|
||||
|
||||
LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'\n", dev->devpath, vol->mount_point);
|
||||
|
||||
if (dev->nr_parts == 0) {
|
||||
rc = _volmgr_start(vol, dev);
|
||||
#if DEBUG_VOLMGR
|
||||
LOG_VOL("_volmgr_start(%s, %s) rc = %d\n", vol->mount_point, dev->dev_fspath ,rc);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* Device has multiple partitions
|
||||
* This is where interesting partition policies could be implemented.
|
||||
* For now just try them in sequence until one succeeds
|
||||
*/
|
||||
|
||||
rc = -ENODEV;
|
||||
int i;
|
||||
for (i = 0; i < dev->nr_parts; i++) {
|
||||
blkdev_t *part = blkdev_lookup_by_devno(dev->major, (i+1));
|
||||
if (!part) {
|
||||
LOGE("Error - unable to lookup partition for blkdev %d:%d\n", dev->major, (i+1));
|
||||
continue;
|
||||
}
|
||||
rc = _volmgr_start(vol, part);
|
||||
#if DEBUG_VOLMGR
|
||||
LOG_VOL("_volmgr_start(%s, %s) rc = %d\n", vol->mount_point, part->dev_fspath, rc);
|
||||
#endif
|
||||
if (!rc)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -ENODEV) {
|
||||
// Assert to make sure each partition had a backing blkdev
|
||||
LOGE("Internal consistency error\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == -ENODATA) {
|
||||
LOGE("Device %s contains no usable filesystems\n", dev->dev_fspath);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void volmgr_reaper_thread_sighandler(int signo)
|
||||
{
|
||||
LOGE("volmgr reaper thread got signal %d\n", signo);
|
||||
}
|
||||
|
||||
static void __reaper_cleanup(void *arg)
|
||||
{
|
||||
volume_t *vol = (volume_t *) arg;
|
||||
|
||||
LOG_VOL("__reaper_cleanup(%s):\n", vol->mount_point);
|
||||
|
||||
vol->worker_running = false;
|
||||
|
||||
// Wake up anyone that was waiting on this thread
|
||||
pthread_mutex_unlock(&vol->worker_sem);
|
||||
|
||||
// Unlock the volume
|
||||
pthread_mutex_unlock(&vol->lock);
|
||||
}
|
||||
|
||||
static void *volmgr_reaper_thread(void *arg)
|
||||
{
|
||||
volume_t *vol = (volume_t *) arg;
|
||||
|
||||
pthread_cleanup_push(__reaper_cleanup, arg);
|
||||
pthread_mutex_lock(&vol->lock);
|
||||
|
||||
vol->worker_running = true;
|
||||
vol->worker_pid = getpid();
|
||||
|
||||
struct sigaction actions;
|
||||
|
||||
memset(&actions, 0, sizeof(actions));
|
||||
sigemptyset(&actions.sa_mask);
|
||||
actions.sa_flags = 0;
|
||||
actions.sa_handler = volmgr_reaper_thread_sighandler;
|
||||
sigaction(SIGUSR1, &actions, NULL);
|
||||
|
||||
LOG_VOL("Worker thread pid %d reaping %s\n", getpid(), vol->mount_point);
|
||||
|
||||
boolean send_sig_kill = false;
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
rc = umount(vol->mount_point);
|
||||
LOG_VOL("volmngr reaper umount(%s) attempt %d rc = %d\n",
|
||||
vol->mount_point, i + 1, rc);
|
||||
if (!rc)
|
||||
break;
|
||||
if (rc && (errno == EINVAL || errno == ENOENT)) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
|
||||
sleep(1);
|
||||
if (!send_sig_kill)
|
||||
send_sig_kill = true;
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
LOG_VOL("Reaper sucessfully unmounted %s\n", vol->mount_point);
|
||||
volume_setstate(vol, volstate_unmounted);
|
||||
} else {
|
||||
LOGE("Unable to unmount!! (%d)\n", rc);
|
||||
}
|
||||
|
||||
out:
|
||||
pthread_cleanup_pop(1);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void volmgr_uncage_reaper(volume_t *vol)
|
||||
{
|
||||
if (vol->worker_running) {
|
||||
LOGE("Worker thread is currently running.. waiting..\n");
|
||||
pthread_mutex_lock(&vol->worker_sem);
|
||||
LOG_VOL("Worker thread now available\n");
|
||||
}
|
||||
|
||||
vol->worker_args.fs = NULL;
|
||||
vol->worker_args.dev = NULL;
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol);
|
||||
}
|
||||
|
||||
static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
if (v->state == volstate_mounted || v->state == volstate_badremoval) {
|
||||
// Try to unmount right away (5 retries)
|
||||
for (i = 0; i < 5; i++) {
|
||||
rc = umount(v->mount_point);
|
||||
LOG_VOL("volmngr quick stop umount(%s) attempt %d rc = %d\n",
|
||||
v->mount_point, i + 1, rc);
|
||||
if (!rc)
|
||||
break;
|
||||
if (rc && (errno == EINVAL || errno == ENOENT)) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
LOG_VOL("volmgr_stop_volume(%s): Volume unmounted sucessfully\n",
|
||||
v->mount_point);
|
||||
if (emit_statechange)
|
||||
volume_setstate(v, volstate_unmounted);
|
||||
goto out_cb_immed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the volume is still in use, dispatch the stopping to
|
||||
* a thread
|
||||
*/
|
||||
LOG_VOL("Volume %s is busy (%d) - uncaging the reaper\n", v->mount_point, rc);
|
||||
volmgr_uncage_reaper(v);
|
||||
return -EINPROGRESS;
|
||||
} else if (v->state == volstate_checking) {
|
||||
volume_setstate(v, volstate_unmounted);
|
||||
if (v->worker_running) {
|
||||
LOG_VOL("Cancelling worker thread\n");
|
||||
pthread_kill(v->worker_thread, SIGUSR1);
|
||||
} else
|
||||
LOGE("Strange... we were in checking state but worker thread wasn't running..\n");
|
||||
goto out_cb_immed;
|
||||
}
|
||||
|
||||
LOGE("volmgr: nothing to do to stop vol '%s' (in state %d)\n",
|
||||
v->mount_point, v->state);
|
||||
out_cb_immed:
|
||||
if (cb)
|
||||
cb(v, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gracefully stop a volume
|
||||
*/
|
||||
static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *))
|
||||
{
|
||||
return volmgr_stop_volume(v, NULL, cb, true);
|
||||
}
|
||||
|
||||
static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg)
|
||||
{
|
||||
void (* shutdown_cb) (volume_t *) = arg;
|
||||
|
||||
LOG_VOL("Volume %s has been stopped for shutdown\n", v->mount_point);
|
||||
shutdown_cb(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a volume is sucessfully unmounted for UMS enable
|
||||
*/
|
||||
static void _cb_volstopped_for_ums_enable(volume_t *v)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = ums_enable(v->dev->dev_fspath, v->ums_path)) < 0) {
|
||||
LOGE("Error enabling ums (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
volume_setstate(v, volstate_ums);
|
||||
}
|
||||
|
||||
static int volmgr_readconfig(char *cfg_path)
|
||||
{
|
||||
cnode *root = config_node("", "");
|
||||
cnode *node;
|
||||
|
||||
config_load_file(root, cfg_path);
|
||||
node = root->first_child;
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(node->name, "volume"))
|
||||
volmgr_config_volume(node);
|
||||
else
|
||||
LOGE("Skipping unknown configuration node '%s'\n", node->name);
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int volmgr_config_volume(cnode *node)
|
||||
{
|
||||
volume_t *new;
|
||||
int rc = 0;
|
||||
|
||||
if (!(new = malloc(sizeof(volume_t))))
|
||||
return -ENOMEM;
|
||||
memset(new, 0, sizeof(volume_t));
|
||||
|
||||
new->state = volstate_nomedia;
|
||||
pthread_mutex_init(&new->lock, NULL);
|
||||
pthread_mutex_init(&new->worker_sem, NULL);
|
||||
|
||||
cnode *child = node->first_child;
|
||||
|
||||
while (child) {
|
||||
if (!strcmp(child->name, "media_path"))
|
||||
new->media_path = strdup(child->value);
|
||||
else if (!strcmp(child->name, "media_type")) {
|
||||
if (!strcmp(child->value, "mmc"))
|
||||
new->media_type = media_mmc;
|
||||
else {
|
||||
LOGE("Invalid media type '%s'\n", child->value);
|
||||
rc = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
} else if (!strcmp(child->name, "mount_point"))
|
||||
new->mount_point = strdup(child->value);
|
||||
else if (!strcmp(child->name, "ums_path"))
|
||||
new->ums_path = strdup(child->value);
|
||||
else
|
||||
LOGE("Ignoring unknown config entry '%s'\n", child->name);
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
if (!new->media_path || !new->mount_point || new->media_type == media_unknown) {
|
||||
LOGE("Required configuration parameter missing for volume\n");
|
||||
rc = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (!vol_root)
|
||||
vol_root = new;
|
||||
else {
|
||||
volume_t *scan = vol_root;
|
||||
while (scan->next)
|
||||
scan = scan->next;
|
||||
scan->next = new;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
out_free:
|
||||
if (new->media_path)
|
||||
free(new->media_path);
|
||||
if (new->mount_point)
|
||||
free(new->mount_point);
|
||||
if (new->ums_path)
|
||||
free(new->ums_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev)
|
||||
{
|
||||
volume_t *scan = vol_root;
|
||||
while(scan) {
|
||||
if (scan->dev == dev)
|
||||
return scan;
|
||||
scan = scan->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
|
||||
{
|
||||
volume_t *scan = vol_root;
|
||||
volume_t *res = NULL;
|
||||
|
||||
while (scan) {
|
||||
if (fuzzy) {
|
||||
if (!strncmp(media_path, scan->media_path, strlen(scan->media_path))) {
|
||||
if (!res)
|
||||
res = scan;
|
||||
else {
|
||||
LOGE("Warning - multiple matching volumes for media '%s' - using first\n", media_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(media_path, scan->media_path))
|
||||
return scan;
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to bring a volume online
|
||||
* Returns: 0 on success, errno on failure, with the following exceptions:
|
||||
* - ENODATA - Unsupported filesystem type / blank
|
||||
* vol->lock MUST be held!
|
||||
*/
|
||||
static int _volmgr_start(volume_t *vol, blkdev_t *dev)
|
||||
{
|
||||
struct volmgr_fstable_entry *fs;
|
||||
int rc = ENODATA;
|
||||
|
||||
#if DEBUG_VOLMGR
|
||||
LOG_VOL("_volmgr_start(%s, %s):\n", vol->mount_point, dev->dev_fspath);
|
||||
#endif
|
||||
|
||||
for (fs = fs_table; fs->name; fs++) {
|
||||
if (!fs->identify_fn(dev))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fs) {
|
||||
LOGE("No supported filesystems on %s\n", dev->dev_fspath);
|
||||
volume_setstate(vol, volstate_nofs);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
return volmgr_start_fs(fs, vol, dev);
|
||||
}
|
||||
|
||||
// vol->lock MUST be held!
|
||||
static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)
|
||||
{
|
||||
/*
|
||||
* Spawn a thread to do the actual checking / mounting in
|
||||
*/
|
||||
|
||||
if (vol->worker_running) {
|
||||
LOGE("Worker thread is currently running.. waiting..\n");
|
||||
pthread_mutex_lock(&vol->worker_sem);
|
||||
LOG_VOL("Worker thread now available\n");
|
||||
}
|
||||
|
||||
vol->dev = dev;
|
||||
|
||||
vol->worker_args.fs = fs;
|
||||
vol->worker_args.dev = dev;
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __start_fs_thread_lock_cleanup(void *arg)
|
||||
{
|
||||
volume_t *vol = (volume_t *) arg;
|
||||
|
||||
LOG_VOL("__start_fs_thread_lock_cleanup(%s):\n", vol->mount_point);
|
||||
|
||||
vol->worker_running = false;
|
||||
|
||||
// Wake up anyone that was waiting on this thread
|
||||
pthread_mutex_unlock(&vol->worker_sem);
|
||||
|
||||
// Unlock the volume
|
||||
pthread_mutex_unlock(&vol->lock);
|
||||
}
|
||||
|
||||
static void *volmgr_start_fs_thread(void *arg)
|
||||
{
|
||||
volume_t *vol = (volume_t *) arg;
|
||||
|
||||
pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg);
|
||||
pthread_mutex_lock(&vol->lock);
|
||||
|
||||
vol->worker_running = true;
|
||||
vol->worker_pid = getpid();
|
||||
|
||||
struct sigaction actions;
|
||||
|
||||
memset(&actions, 0, sizeof(actions));
|
||||
sigemptyset(&actions.sa_mask);
|
||||
actions.sa_flags = 0;
|
||||
actions.sa_handler = volmgr_start_fs_thread_sighandler;
|
||||
sigaction(SIGUSR1, &actions, NULL);
|
||||
|
||||
struct volmgr_fstable_entry *fs = vol->worker_args.fs;
|
||||
blkdev_t *dev = vol->worker_args.dev;
|
||||
int rc;
|
||||
|
||||
LOG_VOL("Worker thread pid %d starting %s fs %s on %s\n", getpid(), fs->name, dev->dev_fspath, vol->mount_point);
|
||||
|
||||
if (fs->check_fn) {
|
||||
LOG_VOL("Starting %s filesystem check on %s\n", fs->name, dev->dev_fspath);
|
||||
volume_setstate(vol, volstate_checking);
|
||||
pthread_mutex_unlock(&vol->lock);
|
||||
rc = fs->check_fn(dev);
|
||||
pthread_mutex_lock(&vol->lock);
|
||||
if (vol->state != volstate_checking) {
|
||||
LOG_VOL("filesystem check aborted\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
LOG_VOL("%s filesystem check failed on %s\n", fs->name, dev->dev_fspath);
|
||||
goto out_unmountable;
|
||||
}
|
||||
LOG_VOL("%s filesystem check of %s OK\n", fs->name, dev->dev_fspath);
|
||||
}
|
||||
|
||||
rc = fs->mount_fn(dev, vol);
|
||||
if (!rc) {
|
||||
LOG_VOL("Sucessfully mounted %s filesystem %s on %s\n", fs->name, dev->devpath, vol->mount_point);
|
||||
volume_setstate(vol, volstate_mounted);
|
||||
goto out;
|
||||
}
|
||||
|
||||
LOGE("%s filesystem mount of %s failed (%d)\n", fs->name, dev->devpath, rc);
|
||||
|
||||
out_unmountable:
|
||||
volume_setstate(vol, volstate_damaged);
|
||||
out:
|
||||
pthread_cleanup_pop(1);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void volmgr_start_fs_thread_sighandler(int signo)
|
||||
{
|
||||
LOGE("volmgr thread got signal %d\n", signo);
|
||||
}
|
||||
|
||||
static void volume_setstate(volume_t *vol, volume_state_t state)
|
||||
{
|
||||
LOG_VOL("Volume %s state change from %d -> %d\n", vol->mount_point, vol->state, state);
|
||||
|
||||
vol->state = state;
|
||||
|
||||
char *prop_val = conv_volstate_to_propstr(vol->state);
|
||||
|
||||
property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
|
||||
volume_send_state(vol);
|
||||
}
|
||||
|
||||
static int volume_send_state(volume_t *vol)
|
||||
{
|
||||
char *event = conv_volstate_to_eventstr(vol->state);
|
||||
|
||||
return send_msg_with_data(event, vol->mount_point);
|
||||
}
|
||||
|
||||
static char *conv_volstate_to_eventstr(volume_state_t state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; volume_state_strings[i].event != NULL; i++) {
|
||||
if (volume_state_strings[i].state == state)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!volume_state_strings[i].event)
|
||||
LOGE("conv_volstate_to_eventstr(%d): Invalid state\n", state);
|
||||
return volume_state_strings[i].event;
|
||||
}
|
||||
|
||||
static char *conv_volstate_to_propstr(volume_state_t state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; volume_state_strings[i].event != NULL; i++) {
|
||||
if (volume_state_strings[i].state == state)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!volume_state_strings[i].event)
|
||||
LOGE("conv_volstate_to_propval(%d): Invalid state\n", state);
|
||||
return volume_state_strings[i].property_val;
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _VOLMGR_H
|
||||
#define _VOLMGR_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "blkdev.h"
|
||||
#include "media.h"
|
||||
|
||||
#define PROP_EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
|
||||
|
||||
// these must match the corresponding states in the MediaState enum.
|
||||
// A path to the volume mount point follows the colon
|
||||
typedef enum volume_state {
|
||||
volstate_unknown,
|
||||
|
||||
volstate_nomedia,
|
||||
#define VOLD_EVT_NOMEDIA "volume_nomedia:"
|
||||
#define VOLD_ES_PVAL_NOMEDIA "removed"
|
||||
|
||||
volstate_unmounted,
|
||||
#define VOLD_EVT_UNMOUNTED "volume_unmounted:"
|
||||
#define VOLD_ES_PVAL_UNMOUNTED "unmounted"
|
||||
|
||||
volstate_checking,
|
||||
#define VOLD_EVT_CHECKING "volume_checking:"
|
||||
#define VOLD_ES_PVAL_CHECKING "checking"
|
||||
|
||||
volstate_mounted,
|
||||
#define VOLD_EVT_MOUNTED "volume_mounted:"
|
||||
#define VOLD_ES_PVAL_MOUNTED "mounted"
|
||||
|
||||
volstate_mounted_ro,
|
||||
#define VOLD_EVT_MOUNTED_RO "volume_mounted_ro:"
|
||||
#define VOLD_ES_PVAL_MOUNTED_RO "mounted_ro"
|
||||
|
||||
volstate_badremoval,
|
||||
#define VOLD_EVT_BADREMOVAL "volume_badremoval:"
|
||||
#define VOLD_ES_PVAL_BADREMOVAL "bad_removal"
|
||||
|
||||
volstate_damaged,
|
||||
#define VOLD_EVT_DAMAGED "volume_damaged:"
|
||||
#define VOLD_ES_PVAL_DAMAGED "unmountable"
|
||||
|
||||
volstate_nofs,
|
||||
#define VOLD_EVT_NOFS "volume_nofs:"
|
||||
#define VOLD_ES_PVAL_NOFS "nofs"
|
||||
|
||||
volstate_ums,
|
||||
#define VOLD_EVT_UMS "volume_ums:"
|
||||
#define VOLD_ES_PVAL_UMS "shared"
|
||||
|
||||
volstate_ejecting,
|
||||
#define VOLD_EVT_EJECTING "volume_ejecting:"
|
||||
#define VOLD_ES_PVAL_EJECTING "ejecting"
|
||||
} volume_state_t;
|
||||
|
||||
struct volume;
|
||||
|
||||
struct volmgr_fstable_entry {
|
||||
char *name;
|
||||
int (*identify_fn) (blkdev_t *dev);
|
||||
int (*check_fn) (blkdev_t *dev);
|
||||
int (*mount_fn) (blkdev_t *dev, struct volume *vol);
|
||||
};
|
||||
|
||||
struct volmgr_start_args {
|
||||
struct volmgr_fstable_entry *fs;
|
||||
blkdev_t *dev;
|
||||
};
|
||||
|
||||
typedef struct volume {
|
||||
char *media_path;
|
||||
media_type_t media_type;
|
||||
char *mount_point;
|
||||
char *ums_path;
|
||||
|
||||
pthread_mutex_t lock;
|
||||
volume_state_t state;
|
||||
blkdev_t *dev;
|
||||
pid_t worker_pid;
|
||||
pthread_t worker_thread;
|
||||
struct volmgr_start_args worker_args;
|
||||
boolean worker_running;
|
||||
pthread_mutex_t worker_sem;
|
||||
|
||||
struct volume *next;
|
||||
} volume_t;
|
||||
|
||||
int volmgr_consider_disk(blkdev_t *dev);
|
||||
int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *));
|
||||
int volmgr_send_states(void);
|
||||
int volmgr_enable_ums(boolean enable);
|
||||
int volmgr_stop_volume_by_mountpoint(char *mount_point);
|
||||
int volmgr_start_volume_by_mountpoint(char *mount_point);
|
||||
|
||||
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded);
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
/*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "volmgr.h"
|
||||
#include "volmgr_ext3.h"
|
||||
|
||||
#define EXT3_DEBUG 0
|
||||
|
||||
int ext3_identify(blkdev_t *dev)
|
||||
{
|
||||
#if EXT3_DEBUG
|
||||
LOG_VOL("ext3_identify(%s):\n", dev->dev_fspath);
|
||||
#endif
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int ext3_check(blkdev_t *dev)
|
||||
{
|
||||
#if EXT3_DEBUG
|
||||
LOG_VOL("ext3_check(%s):\n", dev->dev_fspath);
|
||||
#endif
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int ext3_mount(blkdev_t *dev, volume_t *vol)
|
||||
{
|
||||
#if EXT3_DEBUG
|
||||
LOG_VOL("ext3_mount(%s, %s):\n", dev->dev_fspath, vol->mount_point);
|
||||
#endif
|
||||
return -ENOSYS;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _VOLMGR_EXT3_H
|
||||
#define _VOLMGR_EXT3_H
|
||||
|
||||
#include "volmgr.h"
|
||||
#include "blkdev.h"
|
||||
|
||||
|
||||
|
||||
int ext3_identify(blkdev_t *blkdev);
|
||||
int ext3_check(blkdev_t *blkdev);
|
||||
int ext3_mount(blkdev_t *blkdev, volume_t *vol);
|
||||
#endif
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
/*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "vold.h"
|
||||
#include "volmgr.h"
|
||||
#include "volmgr_vfat.h"
|
||||
#include "logwrapper.h"
|
||||
|
||||
#define VFAT_DEBUG 0
|
||||
|
||||
static char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
|
||||
|
||||
int vfat_identify(blkdev_t *dev)
|
||||
{
|
||||
#if VFAT_DEBUG
|
||||
LOG_VOL("vfat_identify(%s):\n", dev->dev_fspath);
|
||||
#endif
|
||||
return 0; // XXX: Implement
|
||||
}
|
||||
|
||||
int vfat_check(blkdev_t *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if VFAT_DEBUG
|
||||
LOG_VOL("vfat_check(%s):\n", dev->dev_fspath);
|
||||
#endif
|
||||
|
||||
if (access(FSCK_MSDOS_PATH, X_OK)) {
|
||||
LOGE("vfat_check(%s): %s not found (skipping checks)\n",
|
||||
FSCK_MSDOS_PATH, dev->dev_fspath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef VERIFY_PASS
|
||||
char *args[7];
|
||||
args[0] = FSCK_MSDOS_PATH;
|
||||
args[1] = "-v";
|
||||
args[2] = "-V";
|
||||
args[3] = "-w";
|
||||
args[4] = "-p";
|
||||
args[5] = dev->dev_fspath;
|
||||
args[6] = NULL;
|
||||
rc = logwrap(6, args);
|
||||
#else
|
||||
char *args[6];
|
||||
args[0] = FSCK_MSDOS_PATH;
|
||||
args[1] = "-v";
|
||||
args[2] = "-w";
|
||||
args[3] = "-p";
|
||||
args[4] = dev->dev_fspath;
|
||||
args[5] = NULL;
|
||||
rc = logwrap(5, args);
|
||||
#endif
|
||||
|
||||
if (rc == 0) {
|
||||
LOG_VOL("Filesystem check completed OK\n");
|
||||
return 0;
|
||||
} else if (rc == 1) {
|
||||
LOG_VOL("Filesystem check failed (general failure)\n");
|
||||
return -EINVAL;
|
||||
} else if (rc == 2) {
|
||||
LOG_VOL("Filesystem check failed (invalid usage)\n");
|
||||
return -EIO;
|
||||
} else if (rc == 4) {
|
||||
LOG_VOL("Filesystem check completed (errors fixed)\n");
|
||||
} else {
|
||||
LOG_VOL("Filesystem check failed (unknown exit code %d)\n", rc);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfat_mount(blkdev_t *dev, volume_t *vol)
|
||||
{
|
||||
int flags, rc;
|
||||
|
||||
#if VFAT_DEBUG
|
||||
LOG_VOL("vfat_mount(%s, %s):\n", dev->dev_fspath, vol->mount_point);
|
||||
#endif
|
||||
|
||||
flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
|
||||
rc = mount(dev->dev_fspath, vol->mount_point, "vfat", flags,
|
||||
"utf8,uid=1000,gid=1000,fmask=711,dmask=700");
|
||||
|
||||
if (rc && errno == EROFS) {
|
||||
LOGE("vfat_mount(%s, %s): Read only filesystem - retrying mount RO\n",
|
||||
dev->dev_fspath, vol->mount_point);
|
||||
flags |= MS_RDONLY;
|
||||
rc = mount(dev->dev_fspath, vol->mount_point, "vfat", flags,
|
||||
"utf8,uid=1000,gid=1000,fmask=711,dmask=700");
|
||||
}
|
||||
|
||||
#if VFAT_DEBUG
|
||||
LOG_VOL("vfat_mount(%s, %s): mount rc = %d\n", dev->dev_fspath,
|
||||
vol->mount_point, rc);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _VOLMGR_VFAT_H
|
||||
#define _VOLMGR_VFAT_H
|
||||
|
||||
#include "volmgr.h"
|
||||
#include "blkdev.h"
|
||||
|
||||
|
||||
|
||||
int vfat_identify(blkdev_t *blkdev);
|
||||
int vfat_check(blkdev_t *blkdev);
|
||||
int vfat_mount(blkdev_t *blkdev, volume_t *vol);
|
||||
#endif
|
Loading…
Reference in New Issue