diff options
58 files changed, 2291 insertions, 876 deletions
@@ -859,8 +859,20 @@ int adb_main(int is_daemon) property_get("ro.kernel.qemu", value, ""); if (strcmp(value, "1") != 0) { property_get("ro.secure", value, ""); - if (strcmp(value, "1") == 0) + if (strcmp(value, "1") == 0) { + // don't run as root if ro.secure is set... secure = 1; + + // ... except we allow running as root in userdebug builds if the + // service.adb.root property has been set by the "adb root" command + property_get("ro.debuggable", value, ""); + if (strcmp(value, "1") == 0) { + property_get("service.adb.root", value, ""); + if (strcmp(value, "1") == 0) { + secure = 0; + } + } + } } /* don't listen on port 5037 if we are running in secure mode */ @@ -872,8 +884,10 @@ int adb_main(int is_daemon) ** AID_INPUT to diagnose input issues (getevent) ** AID_INET to diagnose network issues (netcfg, ping) ** AID_GRAPHICS to access the frame buffer + ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) */ - gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS }; + gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, + AID_NET_BT, AID_NET_BT_ADMIN }; setgroups(sizeof(groups)/sizeof(groups[0]), groups); /* then switch user and group to "shell" */ @@ -1080,4 +1094,3 @@ int main(int argc, char **argv) return adb_main(0); #endif } - diff --git a/adb/commandline.c b/adb/commandline.c index be596ce..7410dce 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -147,6 +147,7 @@ void help() " adb get-serialno - prints: <serial-number>\n" " adb status-window - continuously print device status for a specified device\n" " adb remount - remounts the /system partition on the device read-write\n" + " adb root - restarts adb with root permissions\n" "\n" "networking:\n" " adb ppp <tty> [parameters] - Run PPP over USB.\n" @@ -914,6 +915,17 @@ top: return 1; } + if(!strcmp(argv[0], "root")) { + int fd = adb_connect("root:"); + if(fd >= 0) { + read_and_dump(fd); + adb_close(fd); + return 0; + } + fprintf(stderr,"error: %s\n", adb_error()); + return 1; + } + if(!strcmp(argv[0], "bugreport")) { if (argc != 1) { return 1; diff --git a/adb/log_service.c b/adb/log_service.c index 8edf98f..6e9bdee 100644 --- a/adb/log_service.c +++ b/adb/log_service.c @@ -22,7 +22,7 @@ #include <fcntl.h> #include <errno.h> #include <sys/socket.h> -#include <utils/logger.h> +#include <cutils/logger.h> #include "sysdeps.h" #include "adb.h" diff --git a/adb/services.c b/adb/services.c index e686949..1de55e6 100644 --- a/adb/services.c +++ b/adb/services.c @@ -103,6 +103,34 @@ static void recover_service(int s, void *cookie) adb_close(fd); } +void restart_root_service(int fd, void *cookie) +{ + char buf[100]; + char value[PROPERTY_VALUE_MAX]; + + if (getuid() == 0) { + snprintf(buf, sizeof(buf), "adbd is already running as root\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + } else { + property_get("ro.debuggable", value, ""); + if (strcmp(value, "1") != 0) { + snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n"); + writex(fd, buf, strlen(buf)); + return; + } + + property_set("service.adb.root", "1"); + snprintf(buf, sizeof(buf), "restarting adbd as root\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + + // quit, and init will restart us as root + sleep(1); + exit(1); + } +} + #endif #if 0 @@ -289,6 +317,8 @@ int service_to_fd(const char *name) ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); + } else if(!strncmp(name, "root:", 5)) { + ret = create_service_thread(restart_root_service, NULL); #endif #if 0 } else if(!strncmp(name, "echo:", 5)){ diff --git a/adb/usb_linux.c b/adb/usb_linux.c index 3feee07..32ce0a9 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -292,7 +292,8 @@ static int find_usb_device(const char *base, } } - register_device_callback(devname, local_ep_in, local_ep_out, i, serial, zero_mask); + register_device_callback(devname, local_ep_in, local_ep_out, + interface->bInterfaceNumber, serial, zero_mask); found_device = 1; break; diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 4079a38..e220dbe 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -195,7 +195,7 @@ void usage(void) "\n" "commands:\n" " update <filename> reflash device from update.zip\n" - " flashall 'flash boot' + 'flash system'\n" + " flashall flash boot + recovery + system\n" " flash <partition> [ <filename> ] write a file to a flash partition\n" " erase <partition> erase a flash partition\n" " getvar <variable> display a bootloader variable\n" @@ -588,6 +588,9 @@ int main(int argc, char **argv) } else if(!strcmp(*argv, "reboot-bootloader")) { wants_reboot_bootloader = 1; skip(1); + } else if (!strcmp(*argv, "continue")) { + fb_queue_command("continue", "resuming boot"); + skip(1); } else if(!strcmp(*argv, "boot")) { char *kname = 0; char *rname = 0; diff --git a/include/cutils/logger.h b/include/cutils/logger.h new file mode 100644 index 0000000..3a08019 --- /dev/null +++ b/include/cutils/logger.h @@ -0,0 +1,46 @@ +/* utils/logger.h +** +** Copyright 2007, The Android Open Source Project +** +** This file is dual licensed. It may be redistributed and/or modified +** under the terms of the Apache 2.0 License OR version 2 of the GNU +** General Public License. +*/ + +#ifndef _UTILS_LOGGER_H +#define _UTILS_LOGGER_H + +#include <stdint.h> + +struct logger_entry { + uint16_t len; /* length of the payload */ + uint16_t __pad; /* no matter what, we get 2 bytes of padding */ + int32_t pid; /* generating process's pid */ + int32_t tid; /* generating process's tid */ + int32_t sec; /* seconds since Epoch */ + int32_t nsec; /* nanoseconds */ + char msg[0]; /* the entry's payload */ +}; + +#define LOGGER_LOG_MAIN "log/main" +#define LOGGER_LOG_RADIO "log/radio" +#define LOGGER_LOG_EVENTS "log/events" + +#define LOGGER_ENTRY_MAX_LEN (4*1024) +#define LOGGER_ENTRY_MAX_PAYLOAD \ + (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry)) + +#ifdef HAVE_IOCTL + +#include <sys/ioctl.h> + +#define __LOGGERIO 0xAE + +#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ +#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ +#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ +#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ + +#endif // HAVE_IOCTL + +#endif /* _UTILS_LOGGER_H */ diff --git a/include/cutils/logprint.h b/include/cutils/logprint.h index c010809..d6ec480 100644 --- a/include/cutils/logprint.h +++ b/include/cutils/logprint.h @@ -17,8 +17,8 @@ #ifndef _LOGPRINT_H #define _LOGPRINT_H -#include <utils/Log.h> -#include <utils/logger.h> +#include <cutils/log.h> +#include <cutils/logger.h> #include <cutils/event_tag_map.h> #include <pthread.h> diff --git a/include/pixelflinger/format.h b/include/pixelflinger/format.h index 308e560..6b2050c 100644 --- a/include/pixelflinger/format.h +++ b/include/pixelflinger/format.h @@ -42,8 +42,10 @@ enum GGLPixelFormat { // YCbCr formats (SP=semi-planar, P=planar) GGL_PIXEL_FORMAT_YCbCr_422_SP= 0x10, GGL_PIXEL_FORMAT_YCbCr_420_SP= 0x11, - GGL_PIXEL_FORMAT_YCbCr_422_P = 0x14, - GGL_PIXEL_FORMAT_YCbCr_420_P = 0x15, + GGL_PIXEL_FORMAT_YCbCr_422_P = 0x12, + GGL_PIXEL_FORMAT_YCbCr_420_P = 0x13, + GGL_PIXEL_FORMAT_YCbCr_422_I = 0x14, + GGL_PIXEL_FORMAT_YCbCr_420_I = 0x15, // reserved/special formats GGL_PIXEL_FORMAT_Z_16 = 0x18, @@ -60,7 +62,10 @@ enum GGLFormatComponents { GGL_RGBA = 0x1908, GGL_LUMINANCE = 0x1909, GGL_LUMINANCE_ALPHA = 0x190A, - GGL_Y_CB_CR = 0x8000, + GGL_Y_CB_CR_SP = 0x8000, + GGL_Y_CB_CR = GGL_Y_CB_CR_SP, + GGL_Y_CB_CR_P = 0x8001, + GGL_Y_CB_CR_I = 0x8002, }; enum GGLFormatComponentIndex { diff --git a/init/devices.c b/init/devices.c index efe3ad0..e0b1f1f 100644 --- a/init/devices.c +++ b/init/devices.c @@ -123,14 +123,13 @@ static struct perms_ devperms[] = { { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 }, + { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 }, { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, - { "/dev/htc-acoustic", 0640, AID_RADIO, AID_RADIO, 0 }, - { "/dev/snd/", 0664, AID_SYSTEM, AID_AUDIO, 1 }, { NULL, 0, 0, 0, 0 }, }; diff --git a/init/property_service.c b/init/property_service.c index 7a6416b..0bc6239 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -69,6 +69,7 @@ struct { { "dhcp.", AID_DHCP }, { "debug.", AID_SHELL }, { "log.", AID_SHELL }, + { "service.adb.root", AID_SHELL }, { "persist.sys.", AID_SYSTEM }, { "persist.service.", AID_SYSTEM }, { NULL, 0 } diff --git a/libcutils/array.c b/libcutils/array.c index ff2c8ff..55ec055 100644 --- a/libcutils/array.c +++ b/libcutils/array.c @@ -18,8 +18,10 @@ #include <assert.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #define INITIAL_CAPACITY (4) +#define MAX_CAPACITY ((int)(UINT_MAX/sizeof(void*))) struct Array { void** contents; @@ -45,13 +47,26 @@ void arrayFree(Array* array) { static int ensureCapacity(Array* array, int capacity) { int oldCapacity = array->capacity; if (capacity > oldCapacity) { - int newCapacity = (oldCapacity == 0) ? INITIAL_CAPACITY : oldCapacity * 2; - - // Keep doubling capacity until we surpass necessary capacity. + int newCapacity = (oldCapacity == 0) ? INITIAL_CAPACITY : oldCapacity; + + // Ensure we're not doing something nasty + if (capacity > MAX_CAPACITY) + return -1; + + // Keep doubling capacity until we surpass necessary capacity. while (newCapacity < capacity) { - newCapacity *= 2; + int newCap = newCapacity*2; + // Handle integer overflows + if (newCap < newCapacity || newCap > MAX_CAPACITY) { + newCap = MAX_CAPACITY; + } + newCapacity = newCap; } - + + // Should not happen, but better be safe than sorry + if (newCapacity < 0 || newCapacity > MAX_CAPACITY) + return -1; + void** newContents; if (array->contents == NULL) { // Allocate new array. @@ -151,5 +166,5 @@ int arraySize(Array* array) { } const void** arrayUnwrap(Array* array) { - return array->contents; + return (const void**)array->contents; } diff --git a/libcutils/strdup8to16.c b/libcutils/strdup8to16.c index 8654b04..63e5ca4 100644 --- a/libcutils/strdup8to16.c +++ b/libcutils/strdup8to16.c @@ -18,6 +18,7 @@ #include <cutils/jstring.h> #include <assert.h> #include <stdlib.h> +#include <limits.h> /* See http://www.unicode.org/reports/tr22/ for discussion * on invalid sequences @@ -48,6 +49,10 @@ extern char16_t * strdup8to16 (const char* s, size_t *out_len) len = strlen8to16(s); + // fail on overflow + if (len && SIZE_MAX/len < sizeof(char16_t)) + return NULL; + // no plus-one here. UTF-16 strings are not null terminated ret = (char16_t *) malloc (sizeof(char16_t) * len); diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c index d9d67b4..ed9d699 100644 --- a/liblog/fake_log_device.c +++ b/liblog/fake_log_device.c @@ -438,31 +438,38 @@ static void showLog(LogState *state, if (*p++ == '\n') numLines++; } if (p > msg && *(p-1) != '\n') numLines++; - + /* * Create an array of iovecs large enough to write all of * the lines with a prefix and a suffix. */ const size_t INLINE_VECS = 6; + const size_t MAX_LINES = ((size_t)~0)/(3*sizeof(struct iovec*)); struct iovec stackVec[INLINE_VECS]; struct iovec* vec = stackVec; - - numLines *= 3; // 3 iovecs per line. - if (numLines > INLINE_VECS) { + size_t numVecs; + + if (numLines > MAX_LINES) + numLines = MAX_LINES; + + numVecs = numLines*3; // 3 iovecs per line. + if (numVecs > INLINE_VECS) { vec = (struct iovec*)malloc(sizeof(struct iovec)*numLines); if (vec == NULL) { msg = "LOG: write failed, no memory"; - numLines = 3; + numVecs = 3; + numLines = 1; + vec = stackVec; } } - + /* * Fill in the iovec pointers. */ p = msg; struct iovec* v = vec; int totalLen = 0; - while (p < end) { + while (numLines > 0 && p < end) { if (prefixLen > 0) { v->iov_base = prefixBuf; v->iov_len = prefixLen; @@ -484,6 +491,7 @@ static void showLog(LogState *state, totalLen += suffixLen; v++; } + numLines -= 1; } /* diff --git a/liblog/logd_write.c b/liblog/logd_write.c index e40d2ce..80867d1 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -25,7 +25,7 @@ #include <stdlib.h> #include <stdarg.h> -#include <utils/logger.h> +#include <cutils/logger.h> #include <cutils/logd.h> #define LOG_BUF_SIZE 1024 diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c index ba98933..bad2e2f 100644 --- a/libnetutils/dhcp_utils.c +++ b/libnetutils/dhcp_utils.c @@ -170,14 +170,19 @@ int dhcp_do_request(const char *interface, */ int dhcp_stop(const char *interface) { + char result_prop_name[PROPERTY_KEY_MAX]; const char *ctrl_prop = "ctl.stop"; const char *desired_status = "stopped"; + snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result", + DHCP_PROP_NAME_PREFIX, + interface); /* Stop the daemon and wait until it's reported to be stopped */ property_set(ctrl_prop, DAEMON_NAME); if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) { return -1; } + property_set(result_prop_name, "failed"); return 0; } diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk index 63a5c84..0cc85d9 100644 --- a/libpixelflinger/Android.mk +++ b/libpixelflinger/Android.mk @@ -48,9 +48,7 @@ ifeq ($(TARGET_ARCH),arm) PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer endif -LOCAL_SHARED_LIBRARIES := \ - libhardware_legacy \ - libcutils +LOCAL_SHARED_LIBRARIES := libcutils ifneq ($(TARGET_ARCH),arm) # Required to define logging functions on the simulator. @@ -68,11 +66,9 @@ LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES) LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS) ifneq ($(BUILD_TINY_ANDROID),true) -# this is for some qemu-tracing cruft, which -# 1. should not depend on libhardware -# 2. should not be build except in emulator builds -# but this at least stops it from breaking the tiny android build -LOCAL_SHARED_LIBRARIES += libhardware +# Really this should go away entirely or at least not depend on +# libhardware, but this at least gets us built. +LOCAL_SHARED_LIBRARIES += libhardware_legacy LOCAL_CFLAGS += -DWITH_LIB_HARDWARE endif diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp index cbbd91a..161e6d6 100644 --- a/libpixelflinger/format.cpp +++ b/libpixelflinger/format.cpp @@ -40,12 +40,12 @@ static GGLFormat const gPixelFormatInfos[] = { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE - { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR },// PIXEL_FORMAT_YCbCr_422_SP - { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR },// PIXEL_FORMAT_YCbCr_420_SP - { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE - { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE - { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE - { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE + { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_SP },// PIXEL_FORMAT_YCbCr_422_SP + { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_SP },// PIXEL_FORMAT_YCbCr_420_SP + { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_P }, // PIXEL_FORMAT_YCbCr_422_P + { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_P }, // PIXEL_FORMAT_YCbCr_420_P + { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_I }, // PIXEL_FORMAT_YCbCr_422_I + { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_I }, // PIXEL_FORMAT_YCbCr_420_I { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp index 75b668d..f700306 100644 --- a/libpixelflinger/scanline.cpp +++ b/libpixelflinger/scanline.cpp @@ -1256,7 +1256,7 @@ finish: void scanline_t32cb16(context_t* c) { int32_t x = c->iterators.xl; - size_t ct = c->iterators.xr - x; + size_t ct = c->iterators.xr - x; int32_t y = c->iterators.y; surface_t* cb = &(c->state.buffers.color); union { @@ -1282,7 +1282,7 @@ last_one: ct--; } - while (ct > 0) { + while (ct >= 2) { s = GGL_RGBA_TO_HOST( *src++ ); sR = (s >> ( 3))&0x1F; sG = (s >> ( 8+2))&0x3F; diff --git a/logcat/Android.mk b/logcat/Android.mk index 3ee051d..f9fd2c9 100644 --- a/logcat/Android.mk +++ b/logcat/Android.mk @@ -16,8 +16,6 @@ include $(CLEAR_VARS) LOCAL_MODULE := event-log-tags -#LOCAL_MODULE_TAGS := user development - # This will install the file in /system/etc # LOCAL_MODULE_CLASS := ETC diff --git a/logcat/event-log-tags b/logcat/event-log-tags index 3d977a5..28cad0a 100644 --- a/logcat/event-log-tags +++ b/logcat/event-log-tags @@ -58,6 +58,9 @@ # This is logged when the partial wake lock (keeping the device awake # regardless of whether the screen is off) is acquired or released. 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3) +# This is logged when battery goes from discharging to charging. +# It lets us count the total amount of time between charges and the discharge level +2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6) # # Leave IDs through 2739 for more power logs # @@ -188,10 +191,23 @@ 30030 am_create_service (Service Record|1|5),(Name|3),(Intent|3),(PID|1|5) # A service is being destroyed 30031 am_destroy_service (Service Record|1|5),(Name|3),(PID|1|5) +# A process has crashed too many times, it is being cleared +30032 am_process_crashed_too_much (Name|3),(PID|1|5) +# An unknown process is trying to attach to the activity manager +30033 am_drop_process (PID|1|5) +# A service has crashed too many times, it is being stopped +30034 am_service_crashed_too_much (Crash Count|1|1),(Component Name|3),(PID|1|5) +# A service is going to be restarted after its process went away +30035 am_schedule_service_restart (Component Name|3),(Time|2|3) +# A client was waiting for a content provider, but its process was lost +30036 am_provider_lost_process (Package Name|3),(UID|1|5),(Name|3) # Out of memory for surfaces. 31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3) +# Re-connecting to input method service because we haven't received its interface +32000 imf_force_reconnect_ime (IME|4),(Time Since Connect|2|3),(Showing|1|1) + # dvm_gc_info: LIST (LONG, LONG, LONG) # # First LONG: @@ -295,19 +311,28 @@ # PDP Setup failures 50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5) -# Call drops +# Call drops 50106 call_drop (cause|1|5), (cid|1|5), (network_type|1|5) # Data network registration failed after successful voice registration 50107 data_network_registration_fail (op_numeric|1|5), (cid|1|5) -# Suspicious status of data connection while radio poweroff +# Suspicious status of data connection while radio poweroff 50108 data_network_status_on_radio_off (dc_state|3), (enable|1|5) +# PDP drop caused by network +50109 pdp_network_drop (cid|1|5), (network_type|1|5) + # Do not change these names without updating tag in: #//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c 51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5) +# db stats. 0 is query, 1 is write (may become more fine grained in the +# future) +52000 db_operation (name|3),(op_type|1|5),(time|2|3) + +# http request/response stats +52001 http_stats (useragent|3),(response|2|3),(processing|2|3),(tx|1|2),(rx|1|2) 60000 viewroot_draw (Draw time|1|3) 60001 viewroot_layout (Layout time|1|3) 60002 view_build_drawing_cache (View created drawing cache|1|5) @@ -315,3 +340,7 @@ # 0 for screen off, 1 for screen on, 2 for key-guard done 70000 screen_toggled (screen_state|1|5) + +# browser stats for diary study +70101 browser_zoom_level_change (start level|1|5),(end level|1|5),(time|2|3) +70102 browser_double_tap_duration (duration|1|3),(time|2|3) diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index d9ca131..3130a1c 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -1,7 +1,6 @@ // Copyright 2006 The Android Open Source Project -#include <utils/misc.h> -#include <utils/logger.h> +#include <cutils/logger.h> #include <cutils/logd.h> #include <cutils/sockets.h> #include <cutils/logprint.h> diff --git a/mountd/Android.mk b/mountd/Android.mk index 2fb7640..16532fa 100644 --- a/mountd/Android.mk +++ b/mountd/Android.mk @@ -18,4 +18,5 @@ LOCAL_CFLAGS := -DCREATE_MOUNT_POINTS=0 LOCAL_SHARED_LIBRARIES := libcutils -include $(BUILD_EXECUTABLE) +# disabled - we are using vold now instead +# include $(BUILD_EXECUTABLE) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 7ff1a74..b2fe8cf 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -4,7 +4,6 @@ include $(CLEAR_VARS) # files that live under /system/etc/... copy_from := \ - etc/mountd.conf \ etc/dbus.conf \ etc/init.goldfish.sh \ etc/hosts diff --git a/rootdir/init.rc b/rootdir/init.rc index 3f8c6a0..a0d6c54 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -87,11 +87,15 @@ on boot # set RLIMIT_NICE to allow priorities from 19 to -20 setrlimit 13 40 40 +# Set timeout value for rmnet stats. + write /sys/devices/virtual/net/rmnet0/timeout_suspend 5000000 + # Define the oom_adj values for the classes of processes that can be # killed by the kernel. These are used in ActivityManagerService. setprop ro.FOREGROUND_APP_ADJ 0 setprop ro.VISIBLE_APP_ADJ 1 setprop ro.SECONDARY_SERVER_ADJ 2 + setprop ro.HOME_APP_ADJ 4 setprop ro.HIDDEN_APP_MIN_ADJ 7 setprop ro.CONTENT_PROVIDER_ADJ 14 setprop ro.EMPTY_APP_ADJ 15 @@ -101,14 +105,18 @@ on boot setprop ro.FOREGROUND_APP_MEM 1536 setprop ro.VISIBLE_APP_MEM 2048 setprop ro.SECONDARY_SERVER_MEM 4096 + setprop ro.HOME_APP_MEM 4096 setprop ro.HIDDEN_APP_MEM 5120 setprop ro.CONTENT_PROVIDER_MEM 5632 setprop ro.EMPTY_APP_MEM 6144 # Write value must be consistent with the above properties. +# Note that the driver only supports 6 slots, so we have HOME_APP at the +# same memory level as services. write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15 write /proc/sys/vm/overcommit_memory 1 + write /proc/sys/vm/min_free_order_shift 4 write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144 # Set init its forked children's oom_adj. @@ -187,8 +195,11 @@ service servicemanager /system/bin/servicemanager onrestart restart zygote onrestart restart media -service mountd /system/bin/mountd - socket mountd stream 0660 root mount +service vold /system/bin/vold + socket vold stream 0660 root mount + +#service mountd /system/bin/mountd +# socket mountd stream 0660 root mount service debuggerd /system/bin/debuggerd @@ -217,8 +228,8 @@ service dbus /system/bin/dbus-daemon --system --nofork user bluetooth group bluetooth net_bt_admin -#STOPSHIP: disable the verbose logging -service hcid /system/bin/logwrapper /system/bin/hcid -d -s -n -f /etc/bluez/hcid.conf +#STOPSHIP: dont use logwrapper in production +service hcid /system/bin/logwrapper /system/bin/hcid -s -n -f /etc/bluez/hcid.conf socket bluetooth stream 660 bluetooth bluetooth socket dbus_bluetooth stream 660 bluetooth bluetooth # init.rc does not yet support applying capabilities, so run as root and diff --git a/toolbox/Android.mk b/toolbox/Android.mk index b0c241e..5a8dc0b 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -41,6 +41,7 @@ TOOLS := \ printenv \ smd \ chmod \ + chown \ mkdosfs \ netstat \ ioctl \ diff --git a/toolbox/chown.c b/toolbox/chown.c new file mode 100644 index 0000000..13617db --- /dev/null +++ b/toolbox/chown.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> + +#include <unistd.h> +#include <time.h> + +int chown_main(int argc, char **argv) +{ + int i; + + if (argc < 3) { + fprintf(stderr, "Usage: chown <USER>[.GROUP] <FILE1> [FILE2] ...\n"); + return 10; + } + + // Copy argv[1] to 'user' so we can truncate it at the period + // if a group id specified. + char user[32]; + char *group = NULL; + strncpy(user, argv[1], sizeof(user)); + if ((group = strchr(user, '.')) != NULL) { + *group++ = '\0'; + } + + // Lookup uid (and gid if specified) + struct passwd *pw; + struct group *grp = NULL; + uid_t uid; + gid_t gid = -1; // passing -1 to chown preserves current group + + pw = getpwnam(user); + if (pw == NULL) { + fprintf(stderr, "No such user '%s'\n", user); + return 10; + } + uid = pw->pw_uid; + + if (group != NULL) { + grp = getgrnam(group); + if (grp == NULL) { + fprintf(stderr, "No such group '%s'\n", group); + return 10; + } + gid = grp->gr_gid; + } + + for (i = 2; i < argc; i++) { + if (chown(argv[i], uid, gid) < 0) { + fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno)); + return 10; + } + } + + return 0; +} + diff --git a/toolbox/insmod.c b/toolbox/insmod.c index d084403..44b9847 100644 --- a/toolbox/insmod.c +++ b/toolbox/insmod.c @@ -45,10 +45,12 @@ bail: return buffer; } +#define min(x,y) ((x) < (y) ? (x) : (y)) int insmod_main(int argc, char **argv) { void *file; - ssize_t size; + ssize_t size = 0; + char opts[1024]; int ret; /* make sure we've got an argument */ @@ -64,9 +66,24 @@ int insmod_main(int argc, char **argv) return -1; } + opts[0] = '\0'; + if (argc > 2) { + int i, len; + char *end = opts + sizeof(opts) - 1; + char *ptr = opts; + + for (i = 2; (i < argc) && (ptr < end); i++) { + len = min(strlen(argv[i]), end - ptr); + memcpy(ptr, argv[i], len); + ptr += len; + *ptr++ = ' '; + *ptr++ = '\0'; + } + *(ptr - 1) = '\0'; + } + /* pass it to the kernel */ - /* XXX options */ - ret = init_module(file, size, ""); + ret = init_module(file, size, opts); if (ret != 0) { fprintf(stderr, "insmod: init_module '%s' failed (%s)\n", diff --git a/toolbox/mkdosfs.c b/toolbox/mkdosfs.c index 9ba9409..744aad1 100644 --- a/toolbox/mkdosfs.c +++ b/toolbox/mkdosfs.c @@ -387,9 +387,8 @@ mkdosfs_main(int argc, char *argv[]) exit(1); } - lseek(fd1, 0, SEEK_SET); - off_t length = lseek(fd1, 0, SEEK_END); - fprintf(stderr, "lseek returned %ld\n", length); + lseek64(fd1, 0, SEEK_SET); + loff_t length = lseek64(fd1, 0, SEEK_END); if (length > 0) { bpb.bsec = length / bpb.bps; bpb.spt = bpb.bsec; @@ -615,8 +614,8 @@ mkdosfs_main(int argc, char *argv[]) fat == 32 && bpb.bkbs != MAXU16 && bss <= bpb.bkbs && x >= bpb.bkbs) { x -= bpb.bkbs; - if (!x && lseek(fd1, 0, SEEK_SET)) - fprintf(stderr, "lseek failed for %s\n", bname); + if (!x && lseek64(fd1, 0, SEEK_SET)) + fprintf(stderr, "lseek64 failed for %s\n", bname); } if (opt_B && x < bss) { if ((n = read(fd1, img, bpb.bps)) == -1) diff --git a/toolbox/top.c b/toolbox/top.c index 0f40a0c..dcc0843 100644 --- a/toolbox/top.c +++ b/toolbox/top.c @@ -41,15 +41,20 @@ struct cpu_info { long unsigned utime, ntime, stime, itime; + long unsigned iowtime, irqtime, sirqtime; }; +#define PROC_NAME_LEN 64 +#define THREAD_NAME_LEN 32 + struct proc_info { struct proc_info *next; pid_t pid; pid_t tid; uid_t uid; gid_t gid; - char name[256]; + char name[PROC_NAME_LEN]; + char tname[THREAD_NAME_LEN]; char state; long unsigned utime; long unsigned stime; @@ -69,7 +74,7 @@ struct proc_list { #define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } #define INIT_PROCS 50 -#define THREAD_MULT 4 +#define THREAD_MULT 8 static struct proc_info **old_procs, **new_procs; static int num_old_procs, num_new_procs; static struct proc_info *free_procs; @@ -228,7 +233,8 @@ static void read_procs(void) { file = fopen("/proc/stat", "r"); if (!file) die("Could not open /proc/stat.\n"); - fscanf(file, "cpu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime, &new_cpu.itime); + fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime, + &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime); fclose(file); proc_num = 0; @@ -237,7 +243,9 @@ static void read_procs(void) { continue; pid = atoi(pid_dir->d_name); - + + struct proc_info cur_proc; + if (!threads) { proc = alloc_proc(); @@ -254,6 +262,12 @@ static void read_procs(void) { proc->num_threads = 0; } else { + sprintf(filename, "/proc/%d/cmdline", pid); + read_cmdline(filename, &cur_proc); + + sprintf(filename, "/proc/%d/status", pid); + read_status(filename, &cur_proc); + proc = NULL; } @@ -275,11 +289,9 @@ static void read_procs(void) { sprintf(filename, "/proc/%d/task/%d/stat", pid, tid); read_stat(filename, proc); - sprintf(filename, "/proc/%d/task/%d/cmdline", pid, tid); - read_cmdline(filename, proc); - - sprintf(filename, "/proc/%d/task/%d/status", pid, tid); - read_status(filename, proc); + strcpy(proc->name, cur_proc.name); + proc->uid = cur_proc.uid; + proc->gid = cur_proc.gid; add_proc(proc_num++, proc); } else { @@ -315,8 +327,9 @@ static int read_stat(char *filename, struct proc_info *proc) { if (!open_paren || !close_paren) return 1; *open_paren = *close_paren = '\0'; - strcpy(proc->name, open_paren + 1); - + strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN); + proc->tname[THREAD_NAME_LEN-1] = 0; + /* Scan rest of string. */ sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld", @@ -347,8 +360,11 @@ static int read_cmdline(char *filename, struct proc_info *proc) { if (!file) return 1; fgets(line, MAX_LINE, file); fclose(file); - if (strlen(line) > 0) - strcpy(proc->name, line); + if (strlen(line) > 0) { + strncpy(proc->name, line, PROC_NAME_LEN); + proc->name[PROC_NAME_LEN-1] = 0; + } else + proc->name[0] = 0; return 0; } @@ -391,16 +407,34 @@ static void print_procs(void) { } } - total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime) - - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime); + total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime + + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime) + - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime + + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime); qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp); printf("\n\n\n"); + printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n", + ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time, + ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time, + ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time, + ((new_cpu.irqtime + new_cpu.sirqtime) + - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time); + printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n", + new_cpu.utime - old_cpu.utime, + new_cpu.ntime - old_cpu.ntime, + new_cpu.stime - old_cpu.stime, + new_cpu.itime - old_cpu.itime, + new_cpu.iowtime - old_cpu.iowtime, + new_cpu.irqtime - old_cpu.irqtime, + new_cpu.sirqtime - old_cpu.sirqtime, + total_delta_time); + printf("\n"); if (!threads) printf("%5s %4s %1s %5s %7s %7s %-8s %s\n", "PID", "CPU%", "S", "#THR", "VSS", "RSS", "UID", "Name"); else - printf("%5s %5s %4s %1s %7s %7s %-8s %s\n", "PID", "TID", "CPU%", "S", "VSS", "RSS", "UID", "Name"); + printf("%5s %5s %4s %1s %7s %7s %-8s %-15s %s\n", "PID", "TID", "CPU%", "S", "VSS", "RSS", "UID", "Thread", "Proc"); for (i = 0; i < num_new_procs; i++) { proc = new_procs[i]; @@ -423,10 +457,10 @@ static void print_procs(void) { } if (!threads) printf("%5d %3ld%% %c %5d %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, - proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name); + proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name[0] != 0 ? proc->name : proc->tname); else - printf("%5d %5d %3ld%% %c %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->tid, proc->delta_time * 100 / total_delta_time, proc->state, - proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name); + printf("%5d %5d %3ld%% %c %6ldK %6ldK %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->delta_time * 100 / total_delta_time, proc->state, + proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->tname, proc->name); } } diff --git a/vold/Android.mk b/vold/Android.mk index 465849f..3dd9f87 100644 --- a/vold/Android.mk +++ b/vold/Android.mk @@ -1,7 +1,3 @@ -BUILD_VOLD := false - -ifeq ($(BUILD_VOLD),true) - LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -10,7 +6,6 @@ LOCAL_SRC_FILES:= \ vold.c \ cmd_dispatch.c \ uevent.c \ - inotify.c \ mmc.c \ misc.c \ blkdev.c \ @@ -22,6 +17,9 @@ LOCAL_SRC_FILES:= \ volmgr_ext3.c \ logwrapper.c \ ProcessKiller.c\ + switch.c \ + format.c \ + devmapper.c LOCAL_MODULE:= vold @@ -32,5 +30,3 @@ LOCAL_CFLAGS := LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) - -endif diff --git a/vold/ProcessKiller.c b/vold/ProcessKiller.c index eeaae04..fc3eb37 100644 --- a/vold/ProcessKiller.c +++ b/vold/ProcessKiller.c @@ -112,7 +112,7 @@ static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint) { char name[PATH_MAX]; GetProcessName(pid, name); - LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link); + LOG_ERROR("process %s (%d) has open file %s", name, pid, link); fileOpen = true; } } @@ -140,7 +140,7 @@ static boolean CheckFileMaps(int pid, const char* mountPoint) { char name[PATH_MAX]; GetProcessName(pid, name); - LOG_ERROR("process %s (%d) has open file map for %s\n", name, pid, path); + LOG_ERROR("process %s (%d) has open file map for %s", name, pid, path); mapOpen = true; } } @@ -159,7 +159,7 @@ static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, c { char name[PATH_MAX]; GetProcessName(pid, name); - LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint); + LOG_ERROR("process %s (%d) has %s in %s", name, pid, message, mountPoint); return true; } else @@ -182,7 +182,7 @@ void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *ex DIR* dir; struct dirent* de; - LOG_ERROR("KillProcessesWithOpenFiles %s\n", mountPoint); + LOG_ERROR("KillProcessesWithOpenFiles %s", mountPoint); dir = opendir("/proc"); if (!dir) return; @@ -205,14 +205,14 @@ void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *ex for (i = 0; i < num_excluded; i++) { if (pid == excluded[i]) { - LOG_ERROR("I just need a little more TIME captain!\n"); + LOG_ERROR("I just need a little more TIME captain!"); hit = true; break; } } if (!hit) { - LOG_ERROR("Killing process %d\n", pid); + LOG_ERROR("Killing process %d", pid); kill(pid, (sigkill ? SIGKILL : SIGTERM)); } } diff --git a/vold/blkdev.c b/vold/blkdev.c index f7907b2..981d0f2 100644 --- a/vold/blkdev.c +++ b/vold/blkdev.c @@ -27,6 +27,7 @@ #include <sys/mman.h> #include <linux/fs.h> +#include <linux/msdos_fs.h> #include "vold.h" #include "blkdev.h" @@ -37,158 +38,145 @@ 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 minor, char *type, struct media *media); -int blkdev_handle_devicefile_removed(blkdev_t *blk, char *dev_fspath) +static int fat_valid_media(unsigned char media) +{ + return 0xf8 <= media || media == 0xf0; +} + +char *blkdev_get_devpath(blkdev_t *blk) { -#if DEBUG_BLKDEV - LOG_VOL("blkdev_handle_devicefile_removed(%s):\n", dev_fspath); -#endif - blkdev_dev_fspath_set(blk, NULL); - return 0; + char *dp = malloc(256); + sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor); + return dp; } -int blkdev_handle_devicefile_created(blkdev_t *blk, char *dev_fspath) +int blkdev_refresh(blkdev_t *blk) { - 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); + int fd = 0; + char *devpath = NULL; + unsigned char *block = NULL; + int i, rc; - 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 (!(block = malloc(512))) + goto out; /* - * If we're a disk, then read the partition table. Otherwise we're - * a partition so get the partition type + * Get the device size */ - disk = blk->disk; + devpath = blkdev_get_devpath(blk); - int fd; - - if ((fd = open(disk->dev_fspath, O_RDWR)) < 0) { - LOGE("Unable to open device '%s' (%s)\n", disk->dev_fspath, strerror(errno)); + if ((fd = open(devpath, O_RDONLY)) < 0) { + LOGE("Unable to open device '%s' (%s)", devpath, strerror(errno)); return -errno; } if (ioctl(fd, BLKGETSIZE, &blk->nr_sec)) { - LOGE("Unable to get device size (%m)\n"); + LOGE("Unable to get device size (%m)"); return -errno; } + close(fd); + free(devpath); -#if DEBUG_BLKDEV - LOG_VOL("New device '%s' size = %u sectors\n", dev_fspath, blk->nr_sec); -#endif + /* + * Open the disk partition table + */ + devpath = blkdev_get_devpath(blk->disk); + if ((fd = open(devpath, O_RDONLY)) < 0) { + LOGE("Unable to open device '%s' (%s)", devpath, + strerror(errno)); + free(devpath); + return -errno; + } - void *raw_pt; - unsigned char *chr_pt; - int i; + free(devpath); - 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 ((rc = read(fd, block, 512)) != 512) { + LOGE("Unable to read device partition table (%d, %s)", + rc, strerror(errno)); + goto out; } + /* + * If we're a disk, then process the partition table. Otherwise we're + * a partition so get the partition type + */ + 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); + if ((block[0x1fe] != 0x55) || (block[0x1ff] != 0xAA)) { + LOGI("Disk %d:%d does not contain a partition table", + blk->major, blk->minor); goto out; } for (i = 0; i < 4; i++) { struct dos_partition part; - dos_partition_dec(raw_pt + DOSPARTOFF + i * sizeof(struct dos_partition), &part); + dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part); + if (part.dp_flag != 0 && part.dp_flag != 0x80) { + struct fat_boot_sector *fb = (struct fat_boot_sector *) &block[0]; + + if (!i && fb->reserved && fb->fats && fat_valid_media(fb->media)) { + LOGI("Detected FAT filesystem in partition table"); + break; + } else { + LOGI("Partition table looks corrupt"); + break; + } + } 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); + dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part); 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: + + if (block) + free(block); + + char tmp[255]; + char tmp2[32]; + sprintf(tmp, "%s (blkdev %d:%d), %u secs (%u MB)", + (blk->type == blkdev_disk ? "Disk" : "Partition"), + blk->major, blk->minor, + blk->nr_sec, + (uint32_t) (((uint64_t) blk->nr_sec * 512) / 1024) / 1024); + + if (blk->type == blkdev_disk) + sprintf(tmp2, " %d partitions", blk->nr_parts); + else + sprintf(tmp2, " type 0x%x", blk->part_type); + + strcat(tmp, tmp2); + LOGI(tmp); + 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); + return 0; } 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); + return _blkdev_create(disk, devpath, major, minor, type, media); } static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major, - int minor, char *type, struct media *media, char *dev_fspath) + int minor, char *type, struct media *media) { blkdev_t *new; struct blkdev_list *list_entry; if (disk && disk->type != blkdev_disk) { - LOGE("Non disk parent specified for blkdev!\n"); + LOGE("Non disk parent specified for blkdev!"); return NULL; } @@ -218,8 +206,6 @@ static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major, new->major = major; new->minor = minor; new->media = media; - if (dev_fspath) - new->dev_fspath = strdup(dev_fspath); new->nr_sec = 0xffffffff; if (disk) @@ -227,12 +213,23 @@ static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major, else new->disk = new; // Note the self disk pointer + /* Create device nodes */ + char nodepath[255]; + mode_t mode = 0666 | S_IFBLK; + dev_t dev = (major << 8) | minor; + + sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor); + if (mknod(nodepath, mode, dev) < 0) { + LOGE("Error making device nodes for '%s' (%s)", + nodepath, strerror(errno)); + } + 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); + LOGE("Unknown block device type '%s'", type); new->type = blkdev_unknown; } @@ -258,8 +255,11 @@ void blkdev_destroy(blkdev_t *blkdev) if (blkdev->devpath) free(blkdev->devpath); - if (blkdev->dev_fspath) - free(blkdev->dev_fspath); + + char nodepath[255]; + sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor); + unlink(nodepath); + free(blkdev); } @@ -272,9 +272,6 @@ blkdev_t *blkdev_lookup_by_path(char *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; } @@ -288,32 +285,12 @@ blkdev_t *blkdev_lookup_by_devno(int maj, int 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. + * Given a disk device, return the number of partitions which + * have yet to be processed. */ int blkdev_get_num_pending_partitions(blkdev_t *blk) { @@ -330,25 +307,13 @@ int blkdev_get_num_pending_partitions(blkdev_t *blk) if (list_scan->dev->major != blk->major) goto next; - if (list_scan->dev->nr_sec != 0xffffffff) + if (list_scan->dev->nr_sec != 0xffffffff && + list_scan->dev->devpath) { 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; - } -} diff --git a/vold/blkdev.h b/vold/blkdev.h index 7818419..e789739 100644 --- a/vold/blkdev.h +++ b/vold/blkdev.h @@ -41,7 +41,6 @@ struct blkdev { int major; int minor; - char *dev_fspath; }; struct blkdev_list { @@ -56,11 +55,10 @@ blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, str 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); +char *blkdev_get_devpath(blkdev_t *blk); + 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); +int blkdev_refresh(blkdev_t *blk); #endif diff --git a/vold/cmd_dispatch.c b/vold/cmd_dispatch.c index 1f48cfc..ab65fd9 100644 --- a/vold/cmd_dispatch.c +++ b/vold/cmd_dispatch.c @@ -33,13 +33,15 @@ 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 int do_format_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_MOUNT_VOLUME, do_mount_volume }, { VOLD_CMD_EJECT_MEDIA, do_eject_media }, + { VOLD_CMD_FORMAT_MEDIA, do_format_media }, { NULL, NULL } }; @@ -49,9 +51,10 @@ int process_framework_command(int socket) char buffer[101]; if ((rc = read(socket, buffer, sizeof(buffer) -1)) < 0) { - LOGE("Unable to read framework command (%s)\n", strerror(errno)); + LOGE("Unable to read framework command (%s)", strerror(errno)); return -errno; - } + } else if (!rc) + return -ECONNRESET; int start = 0; int i; @@ -71,7 +74,7 @@ static void dispatch_cmd(char *cmd) { struct cmd_dispatch *c; - LOG_VOL("dispatch_cmd(%s):\n", cmd); + LOG_VOL("dispatch_cmd(%s):", cmd); for (c = dispatch_table; c->cmd != NULL; c++) { if (!strncmp(c->cmd, cmd, strlen(c->cmd))) { @@ -80,7 +83,7 @@ static void dispatch_cmd(char *cmd) } } - LOGE("No cmd handlers defined for '%s'\n", cmd); + LOGE("No cmd handlers defined for '%s'", cmd); } static int do_send_ums_status(char *cmd) @@ -101,6 +104,11 @@ static int do_mount_volume(char *cmd) return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]); } +static int do_format_media(char *cmd) +{ + return volmgr_format_volume(&cmd[strlen("format_media:")]); +} + static int do_eject_media(char *cmd) { return volmgr_stop_volume_by_mountpoint(&cmd[strlen("eject_media:")]); diff --git a/vold/cmd_dispatch.h b/vold/cmd_dispatch.h index e88874e..f8ba6b3 100644 --- a/vold/cmd_dispatch.h +++ b/vold/cmd_dispatch.h @@ -26,5 +26,6 @@ // 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:" +#define VOLD_CMD_FORMAT_MEDIA "format_media:" #endif diff --git a/vold/devmapper.c b/vold/devmapper.c new file mode 100644 index 0000000..ef44c90 --- /dev/null +++ b/vold/devmapper.c @@ -0,0 +1,463 @@ + +/* + * 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 <fcntl.h> + +#include <sys/mount.h> + +#include <linux/loop.h> +#include <linux/dm-ioctl.h> + +#include <cutils/config_utils.h> +#include <cutils/properties.h> + +#include "vold.h" +#include "devmapper.h" + +#define DEBUG_DEVMAPPER 1 + +static void *_align(void *ptr, unsigned int a) +{ + register unsigned long agn = --a; + + return (void *) (((unsigned long) ptr + agn) & ~agn); +} + +static struct dm_ioctl *_dm_ioctl_setup(struct devmapping *dm, int flags) +{ + void *buffer; + void *p; + const size_t min_size = 16 * 1024; + size_t len = sizeof(struct dm_ioctl); + struct dm_ioctl *io; + struct dm_target_spec *tgt; + int i; + char params[1024]; + char key[80]; + + key[0] = '\0'; + for (i = 0; i < (int) sizeof(dm->key); i++) { + char tmp[8]; + + sprintf(tmp, "%02x", dm->key[i]); + strcat(key, tmp); + } + + char srcdev[128]; + + // XXX: Handle non crypt targets and non twofish (use param) + if (dm->src_type == dmsrc_loopback) + strcpy(srcdev, dm->type_data.loop.loop_dev); + else if (dm->src_type == dmsrc_partition) + strcpy(srcdev, dm->type_data.part.part_dev); + + sprintf(params, "twofish %s 0 %s 0", key, srcdev); + +LOG_VOL("Params = '%s'", params); + + if (len < min_size) + len = min_size; + + if (!(buffer = malloc(len))) { + LOGE("out of memory"); + return NULL; + } + + memset(buffer, 0, len); + io = buffer; + tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)]; + + io->version[0] = 4; + io->version[1] = 0; + io->version[2] = 0; + + io->data_size = len; + io->data_start = sizeof(struct dm_ioctl); + + io->flags = flags; + io->dev = 0; + + io->target_count = 1; + io->event_nr = 1; + strncpy(io->name, dm->target, sizeof(io->name)); + + tgt->status = 0; + tgt->sector_start = 0; + tgt->length = (dm->size_mb * (1024 * 1024)) / 512; + strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type)); + + p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); + strcpy((char *) p, params); + p+= strlen(params) + 1; + + p = _align(p, 8); + tgt->next = p - buffer; + + return io; +} + +static int get_next_available_dm() +{ + int i; + + for (i = 0; i < 8; i++) { + char path[255]; + sprintf(path, "/dev/block/dm-%d", i); + if ((access(path, F_OK) < 0) && (errno == ENOENT)) + return i; + } + + LOGE("Out of device mapper numbers"); + return -1; +} + +static int create_devmapping(struct devmapping *dm) +{ + struct dm_ioctl *io; + int rc, fd; + +#if DEBUG_DEVMAPPER + LOG_VOL("create_devmapping():"); +#endif + + if (dm->dm_no < 0) { + LOGE("Invalid dm_no set"); + return -EINVAL; + } + + if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { + LOGE("Error opening device mapper (%d)", errno); + return -errno; + } + + if (!(io = _dm_ioctl_setup(dm, 0))) { + LOGE("Unable to setup ioctl (out of memory)"); + close(fd); + return -ENOMEM; + } + + if ((rc = ioctl(fd, DM_DEV_CREATE, io)) < 0) { + LOGE("device-mapper create ioctl failed (%d)", errno); + rc = -errno; + goto out_free; + } + + free(io); + + if (!(io = _dm_ioctl_setup(dm, DM_STATUS_TABLE_FLAG))) { + LOGE("Unable to setup ioctl (out of memory)"); + rc = -ENOMEM; + goto out_nofree; + } + + if ((rc = ioctl(fd, DM_TABLE_LOAD, io)) < 0) { + LOGE("device-mapper load ioctl failed (%d)", errno); + rc = -errno; + goto out_free; + } + + free(io); + + if (!(io = _dm_ioctl_setup(dm, 0))) { + LOGE("Unable to setup ioctl (out of memory)"); + rc = -ENOMEM; + goto out_nofree; + } + + if ((rc = ioctl(fd, DM_DEV_SUSPEND, io)) < 0) { + LOGE("device-mapper resume ioctl failed (%d)", errno); + rc = -errno; + goto out_free; + } + +out_free: + free (io); +out_nofree: + close (fd); + return rc; +} + +static int loopback_start(struct devmapping *dm) +{ + int i; + int fd; + char filename[255]; + int rc; + +#if DEBUG_DEVMAPPER + LOG_VOL("loopback_start(%s):", dm->type_data.loop.loop_src); +#endif + + for (i = 0; i < MAX_LOOP; i++) { + struct loop_info info; + + sprintf(filename, "/dev/block/loop%d", i); + + if ((fd = open(filename, O_RDWR)) < 0) { + LOGE("Unable to open %s (%s)", filename, strerror(errno)); + return -errno; + } + + rc = ioctl(fd, LOOP_GET_STATUS, &info); + if (rc < 0 && errno == ENXIO) + break; + + close(fd); + + if (rc < 0) { + LOGE("Unable to get loop status for %s (%s)", filename, + strerror(errno)); + return -errno; + } + } + + if (i == MAX_LOOP) { + LOGE("Out of loop devices"); + return -ENOSPC; + } + + int file_fd; + + if ((file_fd = open(dm->type_data.loop.loop_src, O_RDWR)) < 0) { + LOGE("Unable to open %s (%s)", dm->type_data.loop.loop_src, + strerror(errno)); + return -errno; + } + + if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) { + LOGE("Error setting up loopback interface (%s)", strerror(errno)); + return -errno; + } + + dm->type_data.loop.loop_dev = strdup(filename); + dm->type_data.loop.loop_no = i; + + close(fd); + close(file_fd); + +#if DEBUG_DEVMAPPER + LOG_VOL("Loop setup on %s for %s", dm->type_data.loop.loop_dev, + dm->type_data.loop.loop_src); +#endif + + return 0; +} + +int devmapper_start(struct devmapping *dm) +{ + int rc; + char src_blkdev_path[255]; + +#if DEBUG_DEVMAPPER + LOG_VOL("devmapper_start()"); +#endif + + if (dm->src_type == dmsrc_loopback) { + if ((rc = loopback_start(dm)) < 0) + return rc; + } else if (dm->src_type == dmsrc_partition) { + LOGE("partition maps not yet supported"); + return -ENOSYS; + } else { + LOGE("devmapper_start(): Unsupported source type '%d'", dm->src_type); + return -ENOENT; + } + + /* + * Configure the device mapper + */ + if ((rc = create_devmapping(dm)) < 0) { + LOGE("Failed to create devmapping (%d)", rc); + // XXX: if loopback then tear down + return rc; + } + + return 0; +} + +struct devmapping *devmapper_init(char *src, char *src_type, uint32_t size_mb, + char *target, char *params, char *tgt_fs, char *mediapath) +{ + struct devmapping *dm; + + if (!(dm = malloc(sizeof(struct devmapping)))) { + LOGE("devmapper_init(): out of memory"); + return NULL; + } + + memset(dm, 0, sizeof(struct devmapping)); + + if (!strcmp(src_type, "loopback_file")) { + dm->src_type = dmsrc_loopback; + dm->type_data.loop.loop_src = strdup(src); + } else if (!strncmp(src_type, "partition ", strlen("partition "))) { + dm->src_type = dmsrc_partition; + char *p = strtok(src_type, " "); + if (!p) { + LOGE("Invalid partition specifier"); + goto out_free; + } + dm->type_data.part.part_type = strtoul(p, NULL, 0); + } else { + LOGE("Invalid src_type defined (%s)", src_type); + goto out_free; + } + + // XXX: Validate these + dm->size_mb = size_mb; + dm->target = strdup(target); + dm->params = strdup(params); + dm->tgt_fs = strdup(tgt_fs); + + if ((dm->dm_no = get_next_available_dm()) < 0) + goto out_free; + + sprintf(mediapath, "/devices/virtual/block/dm-%d", dm->dm_no); + + if (!(dm->media = media_create(mediapath, + "unknown", + "unknown", + media_devmapper))) { + LOGE("Unable to create media"); + goto out_free; + } + + return dm; + out_free: + if (dm->target) + free(dm->target); + if (dm->params) + free(dm->params); + if (dm->tgt_fs) + free(dm->tgt_fs); + + free(dm); + return NULL; +} + +int devmapper_genesis(struct devmapping *dm) +{ + + if (dm->src_type == dmsrc_loopback) { + int fd; + + LOG_VOL("devmapper_genesis(): Working on %s", + dm->type_data.loop.loop_src); + + unlink(dm->type_data.loop.loop_src); + + LOG_VOL("devmapper_genesis(): Creating imagefile (%u MB)", + dm->size_mb); + + if ((fd = creat(dm->type_data.loop.loop_src, 0600)) < 0) { + LOGE("Error creating imagefile (%s)", strerror(errno)); + return -errno; + } + + if (ftruncate(fd, (dm->size_mb * (1024 * 1024))) < 0) { + LOGE("Error truncating imagefile (%s)", strerror(errno)); + close(fd); + return -errno; + } + close(fd); + } else if (dm->src_type == dmsrc_partition) { + LOGE("partition maps not yet supported"); + return -ENOSYS; + } + + return devmapper_start(dm); +} + +static int destroy_devmapping(struct devmapping *dm) +{ + struct dm_ioctl *io; + int dmFd; + int rc = 0; + + LOG_VOL("destroy_devmapping():"); + + if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) { + LOGE("Error opening device mapper (%d)", errno); + return -errno; + } + + if (!(io = _dm_ioctl_setup(dm, DM_PERSISTENT_DEV_FLAG))) { + LOGE("Unable to setup ioctl (out of memory)"); + rc = -ENOMEM; + goto out_nofree; + } + + if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) { + LOGE("device-mapper remove ioctl failed (%d)", errno); + rc = -errno; + goto out_free; + } + +out_free: + free (io); +out_nofree: + close (dmFd); + return rc; +} + +static int loopback_stop(struct devmapping *dm) +{ + char devname[255]; + int device_fd; + int rc = 0; + + LOG_VOL("loopback_stop():"); + + device_fd = open(dm->type_data.loop.loop_dev, O_RDONLY); + if (device_fd < 0) { + LOG_ERROR("Failed to open loop (%d)", errno); + return -errno; + } + + if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) { + LOG_ERROR("Failed to destroy loop (%d)", errno); + rc = -errno; + } + + close(device_fd); + return rc; +} + +int devmapper_stop(struct devmapping *dm) +{ + int rc; + + LOG_VOL("devmapper_stop():"); + + if ((rc = destroy_devmapping(dm))) + return rc; + + if (dm->src_type == dmsrc_loopback) { + if ((rc = loopback_stop(dm))) + return rc; + } else if (dm->src_type == dmsrc_partition) { + LOGE("partition maps not yet supported"); + return -ENOSYS; + } + return 0; +} diff --git a/vold/devmapper.h b/vold/devmapper.h new file mode 100644 index 0000000..3d8cab3 --- /dev/null +++ b/vold/devmapper.h @@ -0,0 +1,70 @@ + +/* + * 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 _DEVMAPPER_H +#define _DEVMAPPER_H + +#include <pthread.h> + +#include "vold.h" +#include "blkdev.h" +#include "media.h" + +#define MAX_LOOP 8 + +enum dm_src_type { + dmsrc_unknown, + dmsrc_loopback, + dmsrc_partition, +}; + +struct loop_data { + char *loop_src; + + char *loop_dev; + int loop_no; +}; + +struct part_data { + char part_type; + + char *part_dev; +}; + +struct devmapping { + enum dm_src_type src_type; + union { + struct loop_data loop; + struct part_data part; + } type_data; + + uint32_t size_mb; + char *target; + char *params; + char *tgt_fs; + + unsigned char key[16]; + int dm_no; + + media_t *media; +}; + +struct devmapping *devmapper_init(char *, char *, unsigned int, char *, char *, char *, char *); +int devmapper_start(struct devmapping *); +int devmapper_stop(struct devmapping *); +int devmapper_genesis(struct devmapping *); +#endif diff --git a/vold/format.c b/vold/format.c new file mode 100755 index 0000000..dd0515c --- /dev/null +++ b/vold/format.c @@ -0,0 +1,113 @@ + +/* + * 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 <linux/fs.h> + +#include "vold.h" +#include "blkdev.h" +#include "format.h" +#include "diskmbr.h" +#include "logwrapper.h" + +static char MKDOSFS_PATH[] = "/system/bin/mkdosfs"; +static char MKE2FS_PATH[] = "/system/bin/mke2fs"; + +int format_partition(blkdev_t *part, char *type) +{ + char *devpath; + int rc = -EINVAL; + + devpath = blkdev_get_devpath(part); + + if (!strcmp(type, FORMAT_TYPE_FAT32)) { + char *args[7]; + args[0] = MKDOSFS_PATH; + args[1] = "-F 32"; + args[2] = "-c 32"; + args[3] = "-n 2"; + args[4] = "-O android"; + args[5] = devpath; + args[6] = NULL; + rc = logwrap(6, args); + } else { + char *args[7]; + args[0] = MKE2FS_PATH; + args[1] = "-b 4096"; + args[2] = "-m 1"; + args[3] = "-L android"; + args[4] = "-v"; + args[5] = devpath; + args[6] = NULL; + rc = logwrap(6, args); + } + + free(devpath); + + if (rc == 0) { + LOG_VOL("Filesystem formatted OK"); + return 0; + } else { + LOGE("Format failed (unknokwn exit code %d)", rc); + return -EIO; + } + return 0; +} + +int initialize_mbr(blkdev_t *disk) +{ + int fd, rc; + unsigned char block[512]; + struct dos_partition part; + char *devpath; + + devpath = blkdev_get_devpath(disk); + + memset(&part, 0, sizeof(part)); + part.dp_flag = 0x80; + part.dp_typ = 0xc; + part.dp_start = ((1024 * 64) / 512) + 1; + part.dp_size = disk->nr_sec - part.dp_start; + + memset(block, 0, sizeof(block)); + block[0x1fe] = 0x55; + block[0x1ff] = 0xaa; + + dos_partition_enc(block + DOSPARTOFF, &part); + + if ((fd = open(devpath, O_RDWR)) < 0) { + LOGE("Error opening disk file (%s)", strerror(errno)); + return -errno; + } + free(devpath); + + if (write(fd, block, sizeof(block)) < 0) { + LOGE("Error writing MBR (%s)", strerror(errno)); + close(fd); + return -errno; + } + + if (ioctl(fd, BLKRRPART, NULL) < 0) { + LOGE("Error re-reading partition table (%s)", strerror(errno)); + close(fd); + return -errno; + } + close(fd); + return 0; +} diff --git a/vold/format.h b/vold/format.h new file mode 100644 index 0000000..73cc012 --- /dev/null +++ b/vold/format.h @@ -0,0 +1,26 @@ + +/* + * 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 _FORMAT_H +#define _FORMAT_H + +#define FORMAT_TYPE_EXT2 "ext2" +#define FORMAT_TYPE_FAT32 "fat32" + +int format_partition(blkdev_t *part, char *type); +int initialize_mbr(blkdev_t *disk); +#endif diff --git a/vold/geom_mbr_enc.c b/vold/geom_mbr_enc.c index 755fbba..f1f8339 100644 --- a/vold/geom_mbr_enc.c +++ b/vold/geom_mbr_enc.c @@ -44,6 +44,17 @@ le32dec(const void *buf) return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); } +static __inline void +le32enc(void *pp, uint32_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; + p[2] = (u >> 16) & 0xff; + p[3] = (u >> 24) & 0xff; +} + void dos_partition_dec(void const *pp, struct dos_partition *d) { @@ -60,3 +71,20 @@ dos_partition_dec(void const *pp, struct dos_partition *d) d->dp_start = le32dec(p + 8); d->dp_size = le32dec(p + 12); } + +void +dos_partition_enc(void *pp, struct dos_partition *d) +{ + unsigned char *p = pp; + + p[0] = d->dp_flag; + p[1] = d->dp_shd; + p[2] = d->dp_ssect; + p[3] = d->dp_scyl; + p[4] = d->dp_typ; + p[5] = d->dp_ehd; + p[6] = d->dp_esect; + p[7] = d->dp_ecyl; + le32enc(p + 8, d->dp_start); + le32enc(p + 12, d->dp_size); +} diff --git a/vold/inotify.c b/vold/inotify.c deleted file mode 100644 index a7b789c..0000000 --- a/vold/inotify.c +++ /dev/null @@ -1,270 +0,0 @@ - -/* - * 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; -} diff --git a/vold/logwrapper.c b/vold/logwrapper.c index f803dba..25d2281 100644 --- a/vold/logwrapper.c +++ b/vold/logwrapper.c @@ -95,7 +95,7 @@ void child(int argc, char* argv[]) { // 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)); + "executing %s failed: %s", argv_child[0], strerror(errno)); exit(-1); } } @@ -111,24 +111,24 @@ int logwrap(int argc, char* argv[], pid_t *childPid) /* 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"); + LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty"); 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"); + LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx"); return -1; } pid = fork(); if (pid < 0) { - LOG(LOG_ERROR, "logwrapper", "Failed to fork\n"); + LOG(LOG_ERROR, "logwrapper", "Failed to fork"); 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"); + LOG(LOG_ERROR, "logwrapper", "Problem with child ptty"); return -errno; } diff --git a/vold/media.c b/vold/media.c index f385586..db42a3e 100644 --- a/vold/media.c +++ b/vold/media.c @@ -85,8 +85,8 @@ void media_destroy(media_t *media) free(media->devpath); free(media->name); - if (media->devs) - LOGE("media_destroy(): media still has blkdevs associated with it! Possible leak\n"); + while(media->devs) + media_remove_blkdev(media, media->devs->dev); free(media); } @@ -105,7 +105,7 @@ media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match) list_scan = list_scan->next; } #if DEBUG_MEDIA - LOG_VOL("media_lookup_by_path(): No media found @ %s\n", devpath); + LOG_VOL("media_lookup_by_path(): No media found @ %s", devpath); #endif return NULL; } @@ -114,10 +114,8 @@ 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"); + if (!(list_entry = malloc(sizeof(blkdev_list_t)))) return -ENOMEM; - } list_entry->next = NULL; list_entry->dev = dev; diff --git a/vold/media.h b/vold/media.h index 84c3947..567ce04 100644 --- a/vold/media.h +++ b/vold/media.h @@ -25,7 +25,7 @@ typedef enum media_type { media_unknown, media_mmc, - media_dm + media_devmapper, } media_type_t; typedef struct media { @@ -43,7 +43,7 @@ int mmc_bootstrap() struct dirent *de; if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) { - LOG_ERROR("Unable to open '%s' (%m)\n", SYSFS_CLASS_MMC_PATH); + LOG_ERROR("Unable to open '%s' (%m)", SYSFS_CLASS_MMC_PATH); return -errno; } @@ -55,7 +55,7 @@ int mmc_bootstrap() 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); + LOG_ERROR("Error bootstrapping controller '%s' (%m)", tmp); } closedir(d); @@ -69,10 +69,10 @@ static int mmc_bootstrap_controller(char *sysfs_path) struct dirent *de; #if DEBUG_BOOTSTRAP - LOG_VOL("bootstrap_controller(%s):\n", sysfs_path); + LOG_VOL("bootstrap_controller(%s):", sysfs_path); #endif if (!(d = opendir(sysfs_path))) { - LOG_ERROR("Unable to open '%s' (%m)\n", sysfs_path); + LOG_ERROR("Unable to open '%s' (%m)", sysfs_path); return -errno; } @@ -92,7 +92,7 @@ static int mmc_bootstrap_controller(char *sysfs_path) sprintf(tmp, "%s/%s", sysfs_path, de->d_name); if (mmc_bootstrap_card(tmp) < 0) - LOG_ERROR("Error bootstrapping card '%s' (%m)\n", tmp); + LOG_ERROR("Error bootstrapping card '%s' (%m)", tmp); } // while closedir(d); @@ -111,29 +111,29 @@ static int mmc_bootstrap_card(char *sysfs_path) ssize_t sz; #if DEBUG_BOOTSTRAP - LOG_VOL("bootstrap_card(%s):\n", sysfs_path); + LOG_VOL("bootstrap_card(%s):", 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"); + LOGE("Error getting working dir path"); return -errno; } if (chdir(sysfs_path) < 0) { - LOGE("Unable to chdir to %s (%m)\n", sysfs_path); + LOGE("Unable to chdir to %s (%m)", sysfs_path); return -errno; } if (!getcwd(new_cwd, sizeof(new_cwd))) { - LOGE("Buffer too small for device path\n"); + LOGE("Buffer too small for device path"); return -errno; } if (chdir(saved_cwd) < 0) { - LOGE("Unable to restore working dir\n"); + LOGE("Unable to restore working dir"); return -errno; } @@ -162,7 +162,7 @@ static int mmc_bootstrap_card(char *sysfs_path) uevent_params[3] = (char *) NULL; if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) { - LOGE("Error simulating uevent (%m)\n"); + LOGE("Error simulating uevent (%m)"); return -errno; } @@ -174,7 +174,7 @@ static int mmc_bootstrap_card(char *sysfs_path) sprintf(filename, "/sys%s/block", devpath); if (!access(filename, F_OK)) { if (mmc_bootstrap_block(tmp)) { - LOGE("Error bootstrapping block @ %s\n", tmp); + LOGE("Error bootstrapping block @ %s", tmp); } } @@ -188,13 +188,13 @@ static int mmc_bootstrap_block(char *devpath) struct dirent *de; #if DEBUG_BOOTSTRAP - LOG_VOL("mmc_bootstrap_block(%s):\n", devpath); + LOG_VOL("mmc_bootstrap_block(%s):", devpath); #endif sprintf(blockdir_path, "/sys%s", devpath); if (!(d = opendir(blockdir_path))) { - LOGE("Failed to opendir %s\n", devpath); + LOGE("Failed to opendir %s", devpath); return -errno; } @@ -205,7 +205,7 @@ static int mmc_bootstrap_block(char *devpath) continue; sprintf(tmp, "%s/%s", devpath, de->d_name); if (mmc_bootstrap_mmcblk(tmp)) - LOGE("Error bootstraping mmcblk @ %s\n", tmp); + LOGE("Error bootstraping mmcblk @ %s", tmp); } closedir(d); return 0; @@ -218,11 +218,11 @@ static int mmc_bootstrap_mmcblk(char *devpath) int rc; #if DEBUG_BOOTSTRAP - LOG_VOL("mmc_bootstrap_mmcblk(%s):\n", devpath); + LOG_VOL("mmc_bootstrap_mmcblk(%s):", devpath); #endif if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) { - LOGE("Error bootstrapping mmcblk partition '%s'\n", devpath); + LOGE("Error bootstrapping mmcblk partition '%s'", devpath); return rc; } @@ -238,7 +238,7 @@ static int mmc_bootstrap_mmcblk(char *devpath) 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); + LOGE("Error bootstrapping mmcblk partition '%s'", part_devpath); } } @@ -256,7 +256,7 @@ static int mmc_bootstrap_mmcblk_partition(char *devpath) char line[255]; #if DEBUG_BOOTSTRAP - LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):\n", devpath); + LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):", devpath); #endif sprintf(tmp, "DEVPATH=%s", devpath); @@ -264,7 +264,7 @@ static int mmc_bootstrap_mmcblk_partition(char *devpath) sprintf(filename, "/sys%s/uevent", devpath); if (!(fp = fopen(filename, "r"))) { - LOGE("Unable to open '%s' (%m)\n", filename); + LOGE("Unable to open '%s' (%m)", filename); return -errno; } @@ -280,13 +280,13 @@ static int mmc_bootstrap_mmcblk_partition(char *devpath) fclose(fp); if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) { - LOGE("mmcblk uevent missing required params\n"); + LOGE("mmcblk uevent missing required params"); return -1; } uevent_params[4] = '\0'; if (simulate_uevent("block", devpath, "add", uevent_params) < 0) { - LOGE("Error simulating uevent (%m)\n"); + LOGE("Error simulating uevent (%m)"); return -errno; } return 0; diff --git a/vold/switch.c b/vold/switch.c new file mode 100644 index 0000000..ba9ddb3 --- /dev/null +++ b/vold/switch.c @@ -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 <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <errno.h> + +#include <sys/types.h> + +#include "vold.h" +#include "switch.h" + +#define DEBUG_BOOTSTRAP 0 + +static int mmc_bootstrap_switch(char *sysfs_path); + +int switch_bootstrap() +{ + DIR *d; + struct dirent *de; + + if (!(d = opendir(SYSFS_CLASS_SWITCH_PATH))) { + LOG_ERROR("Unable to open '%s' (%m)", SYSFS_CLASS_SWITCH_PATH); + return -errno; + } + + while ((de = readdir(d))) { + char tmp[255]; + + if (de->d_name[0] == '.') + continue; + + sprintf(tmp, "%s/%s", SYSFS_CLASS_SWITCH_PATH, de->d_name); + if (mmc_bootstrap_switch(tmp)) + LOG_ERROR("Error bootstrapping switch '%s' (%m)", tmp); + } + + closedir(d); + + return 0; +} + +static int mmc_bootstrap_switch(char *sysfs_path) +{ +#if DEBUG_BOOTSTRAP + LOG_VOL("bootstrap_switch(%s):", sysfs_path); +#endif + + char filename[255]; + char name[255]; + char state[255]; + char tmp[255]; + char *uevent_params[3]; + char devpath[255]; + FILE *fp; + + /* + * Read switch name + */ + sprintf(filename, "%s/name", sysfs_path); + if (!(fp = fopen(filename, "r"))) { + LOGE("Error opening switch name path '%s' (%s)", + sysfs_path, strerror(errno)); + return -errno; + } + if (!fgets(name, sizeof(name), fp)) { + LOGE("Unable to read switch name"); + fclose(fp); + return -EIO; + } + fclose(fp); + + name[strlen(name) -1] = '\0'; + sprintf(devpath, "/devices/virtual/switch/%s", name); + sprintf(tmp, "SWITCH_NAME=%s", name); + uevent_params[0] = (char *) strdup(tmp); + + /* + * Read switch state + */ + sprintf(filename, "%s/state", sysfs_path); + if (!(fp = fopen(filename, "r"))) { + LOGE("Error opening switch state path '%s' (%s)", + sysfs_path, strerror(errno)); + return -errno; + } + if (!fgets(state, sizeof(state), fp)) { + LOGE("Unable to read switch state"); + fclose(fp); + return -EIO; + } + fclose(fp); + + state[strlen(state) -1] = '\0'; + sprintf(tmp, "SWITCH_STATE=%s", state); + uevent_params[1] = (char *) strdup(tmp); + + uevent_params[2] = (char *) NULL; + + if (simulate_uevent("switch", devpath, "add", uevent_params) < 0) { + LOGE("Error simulating uevent (%s)", strerror(errno)); + return -errno; + } + + return 0; +} diff --git a/vold/inotify.h b/vold/switch.h index ada42a8..6729f2d 100644 --- a/vold/inotify.h +++ b/vold/switch.h @@ -15,8 +15,11 @@ * limitations under the License. */ -#ifndef _INOTIFY_EVT_H -#define _INOTIFY_EVT_H +#ifndef _SWITCH_H +#define _SWITCH_H +#include "vold.h" + +#define SYSFS_CLASS_SWITCH_PATH "/sys/class/switch" #endif diff --git a/vold/uevent.c b/vold/uevent.c index 6b724d0..d16f315 100644 --- a/vold/uevent.c +++ b/vold/uevent.c @@ -71,6 +71,9 @@ static struct uevent_dispatch dispatch_table[] = { { NULL, NULL } }; +static boolean low_batt = false; +static boolean door_open = true; + int process_uevent_message(int socket) { char buffer[64 * 1024]; // Thank god we're not in the kernel :) @@ -84,12 +87,12 @@ int process_uevent_message(int socket) int rc = 0; if ((count = recv(socket, buffer, sizeof(buffer), 0)) < 0) { - LOGE("Error receiving uevent (%s)\n", strerror(errno)); + LOGE("Error receiving uevent (%s)", strerror(errno)); return -errno; } if (!(event = malloc(sizeof(struct uevent)))) { - LOGE("Error allocating memory (%s)\n", strerror(errno)); + LOGE("Error allocating memory (%s)", strerror(errno)); return -errno; } @@ -120,7 +123,7 @@ int process_uevent_message(int socket) else event->param[param_idx++] = strdup(s); } - s+= (strlen(s) + 1); + s+= strlen(s) + 1; } rc = dispatch_uevent(event); @@ -136,7 +139,7 @@ int simulate_uevent(char *subsys, char *path, char *action, char **params) int i, rc; if (!(event = malloc(sizeof(struct uevent)))) { - LOGE("Error allocating memory (%s)\n", strerror(errno)); + LOGE("Error allocating memory (%s)", strerror(errno)); return -errno; } @@ -151,7 +154,7 @@ int simulate_uevent(char *subsys, char *path, char *action, char **params) else if (!strcmp(action, "remove")) event->action = action_remove; else { - LOGE("Invalid action '%s'\n", action); + LOGE("Invalid action '%s'", action); return -1; } @@ -172,13 +175,16 @@ static int dispatch_uevent(struct uevent *event) { int i; +#if DEBUG_UEVENT + dump_uevent(event); +#endif 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); + LOG_VOL("No uevent handlers registered for '%s' subsystem", event->subsystem); #endif return 0; } @@ -187,12 +193,12 @@ static void dump_uevent(struct uevent *event) { int i; - LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s\n", + LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s", 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]); + LOG_VOL("%s", event->param[i]); } } @@ -220,7 +226,7 @@ static char *get_uevent_param(struct uevent *event, char *param_name) return &event->param[i][strlen(param_name) + 1]; } - LOGE("get_uevent_param(): No parameter '%s' found\n", param_name); + LOGE("get_uevent_param(): No parameter '%s' found", param_name); return NULL; } @@ -232,7 +238,18 @@ static char *get_uevent_param(struct uevent *event, char *param_name) static int handle_powersupply_event(struct uevent *event) { - dump_uevent(event); + char *ps_type = get_uevent_param(event, "POWER_SUPPLY_TYPE"); + char *ps_cap = get_uevent_param(event, "POWER_SUPPLY_CAPACITY"); + + if (!strcasecmp(ps_type, "battery")) { + int capacity = atoi(ps_cap); + + if (capacity < 5) + low_batt = true; + else + low_batt = false; + volmgr_safe_mode(low_batt || door_open); + } return 0; } @@ -241,21 +258,28 @@ 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); + volmgr_enable_ums(false); } + } else if (!strcmp(name, "sd-door")) { + if (!strcmp(state, "open")) + door_open = true; + else + door_open = false; + volmgr_safe_mode(low_batt || door_open); } else - LOG_VOL("handle_switch_event(): Ignoring switch '%s'\n", name); + LOG_VOL("handle_switch_event(): Ignoring switch '%s'", name); return 0; } static int handle_battery_event(struct uevent *event) { - dump_uevent(event); return 0; } @@ -270,12 +294,16 @@ static int handle_block_event(struct uevent *event) /* * Look for backing media for this block device */ - if (!strcmp(get_uevent_param(event, "DEVTYPE"), "disk")) + if (!strncmp(get_uevent_param(event, "DEVPATH"), + "/devices/virtual/", + strlen("/devices/virtual/"))) { + n = 0; + } else 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")); + LOGE("Bad blockdev type '%s'", get_uevent_param(event, "DEVTYPE")); return -EINVAL; } @@ -283,7 +311,7 @@ static int handle_block_event(struct uevent *event) if (!(media = media_lookup_by_path(mediapath, false))) { #if DEBUG_UEVENT - LOG_VOL("No backend media found @ device path '%s'\n", mediapath); + LOG_VOL("No backend media found @ device path '%s'", mediapath); #endif return 0; } @@ -293,7 +321,6 @@ static int handle_block_event(struct uevent *event) if (event->action == action_add) { blkdev_t *disk; - boolean pending = false; /* * If there isn't a disk already its because *we* @@ -301,70 +328,56 @@ static int handle_block_event(struct uevent *event) */ 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; - } + if (!(blkdev = blkdev_create(disk, + event->path, + maj, + min, + media, + get_uevent_param(event, "DEVTYPE")))) { + LOGE("Unable to allocate new blkdev (%m)"); + return -1; } + blkdev_refresh(blkdev); + /* * 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); + LOGE("Unable to add blkdev to card (%d)", 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; - } + LOGI("New blkdev %d.%d on media %s, media path %s, Dpp %d", + blkdev->major, blkdev->minor, media->name, mediapath, + 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 device (%d)", rc); + return rc; } } } else if (event->action == action_remove) { - int rc; + if (!(blkdev = blkdev_lookup_by_devno(maj, min))) + return 0; - if (!(blkdev = blkdev_lookup_by_devno(maj, min))) { -#if DEBUG_UEVENT - LOG_VOL("We aren't handling blkdev @ %s\n", event->path); -#endif + LOGI("Destroying blkdev %d.%d @ %s on media %s", blkdev->major, + blkdev->minor, blkdev->devpath, media->name); + volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy); + + } else if (event->action == action_change) { + if (!(blkdev = blkdev_lookup_by_devno(maj, min))) 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 { + LOGI("Modified blkdev %d.%d @ %s on media %s", blkdev->major, + blkdev->minor, blkdev->devpath, media->name); + + blkdev_refresh(blkdev); + } else { #if DEBUG_UEVENT - LOG_VOL("No handler implemented for action %d\n", event->action); + LOG_VOL("No handler implemented for action %d", event->action); #endif } return 0; @@ -402,28 +415,25 @@ static int handle_mmc_event(struct uevent *event) get_uevent_param(event, "MMC_NAME"), serial, media_mmc))) { - LOGE("Unable to allocate new media (%m)\n"); + LOGE("Unable to allocate new media (%m)"); return -1; } - LOG_VOL("New MMC card '%s' (serial %u) added @ %s\n", media->name, + LOGI("New MMC card '%s' (serial %u) added @ %s", 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); + LOGE("Unable to lookup media '%s'", event->path); return -1; } - LOG_VOL("MMC card '%s' (serial %u) @ %s removed\n", media->name, + LOGI("MMC card '%s' (serial %u) @ %s removed", 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); + LOG_VOL("No handler implemented for action %d", event->action); #endif } @@ -21,6 +21,8 @@ #include "vold.h" #include "ums.h" +#define DEBUG_UMS 0 + static boolean host_connected = false; static boolean ums_enabled = false; @@ -42,7 +44,9 @@ boolean ums_enabled_get() void ums_hostconnected_set(boolean connected) { - LOG_VOL("ums_hostconnected_set(%d):\n", connected); +#if DEBUG_UMS + LOG_VOL("ums_hostconnected_set(%d):", connected); +#endif host_connected = connected; if (!connected) @@ -52,19 +56,19 @@ void ums_hostconnected_set(boolean connected) int ums_enable(char *dev_fspath, char *lun_syspath) { - LOG_VOL("ums_enable(%s, %s):\n", dev_fspath, lun_syspath); + LOG_VOL("ums_enable(%s, %s):", 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)); + LOGE("Unable to open '%s' (%s)", 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)); + LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); close(fd); return -errno; } @@ -75,21 +79,23 @@ int ums_enable(char *dev_fspath, char *lun_syspath) int ums_disable(char *lun_syspath) { - LOG_VOL("ums_disable(%s):\n", lun_syspath); +#if DEBUG_UMS + LOG_VOL("ums_disable(%s):", lun_syspath); +#endif 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)); + LOGE("Unable to open '%s' (%s)", 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)); + LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); close(fd); return -errno; } @@ -107,7 +113,9 @@ int ums_send_status(void) { int rc; - LOG_VOL("ums_send_status():\n"); +#if DEBUG_UMS + LOG_VOL("ums_send_status():"); +#endif rc = send_msg(ums_enabled_get() ? VOLD_EVT_UMS_ENABLED : VOLD_EVT_UMS_DISABLED); diff --git a/vold/vold.c b/vold/vold.c index b2c8eb2..7d50a2f 100644 --- a/vold/vold.c +++ b/vold/vold.c @@ -27,7 +27,6 @@ #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> @@ -57,12 +56,11 @@ 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); + LOGI("Android Volume Daemon version %d.%d", ver_major, ver_minor); /* * Create all the various sockets we'll need @@ -70,29 +68,18 @@ int main(int argc, char **argv) // 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", + LOGE("Obtaining file descriptor socket '%s' failed: %s", VOLD_SOCKET, strerror(errno)); exit(1); } if (listen(door_sock, 4) < 0) { - LOGE("Unable to listen on fd '%d' for socket '%s': %s\n", + LOGE("Unable to listen on fd '%d' for socket '%s': %s", 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); - } + mkdir("/dev/block/vold", 0755); // Socket to listen on for uevent changes memset(&nladdr, 0, sizeof(nladdr)); @@ -102,18 +89,18 @@ int main(int argc, char **argv) if ((uevent_sock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { - LOGE("Unable to create uevent socket: %s\n", strerror(errno)); + LOGE("Unable to create uevent socket: %s", 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)); + LOGE("Unable to set uevent socket options: %s", strerror(errno)); exit(1); } if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { - LOGE("Unable to bind uevent socket: %s\n", strerror(errno)); + LOGE("Unable to bind uevent socket: %s", strerror(errno)); exit(1); } @@ -121,22 +108,22 @@ int main(int argc, char **argv) * Bootstrap */ + // Volume Manager + volmgr_bootstrap(); + // SD Card system mmc_bootstrap(); // USB Mass Storage ums_bootstrap(); - // Volume Manager - volmgr_bootstrap(); - - // Block device system - inotify_bootstrap(); + // Switch + switch_bootstrap(); /* * Main loop */ - + LOG_VOL("Bootstrapping complete"); while(1) { fd_set read_fds; struct timeval to; @@ -146,12 +133,10 @@ int main(int argc, char **argv) to.tv_sec = (60 * 60); to.tv_usec = 0; + FD_ZERO(&read_fds); 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; @@ -163,7 +148,7 @@ int main(int argc, char **argv) } if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) { - LOGE("select() failed (%s)\n", strerror(errno)); + LOGE("select() failed (%s)", strerror(errno)); sleep(1); continue; } @@ -178,42 +163,41 @@ int main(int argc, char **argv) alen = sizeof(addr); + if (fw_sock != -1) { + LOGE("Dropping duplicate framework connection"); + int tmp = accept(door_sock, &addr, &alen); + close(tmp); + continue; + } + if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) { - LOGE("Unable to accept framework connection (%s)\n", + LOGE("Unable to accept framework connection (%s)", strerror(errno)); } - LOG_VOL("Accepted connection from framework\n"); + LOG_VOL("Accepted connection from framework"); if ((rc = volmgr_send_states()) < 0) { - LOGE("Unable to send volmgr status to framework (%d)\n", rc); + LOGE("Unable to send volmgr status to framework (%d)", rc); } } if (FD_ISSET(fw_sock, &read_fds)) { if ((rc = process_framework_command(fw_sock)) < 0) { if (rc == -ECONNRESET) { - LOGE("Framework disconnected\n"); + LOGE("Framework disconnected"); close(fw_sock); fw_sock = -1; } else { - LOGE("Error processing framework command (%s)\n", + LOGE("Error processing framework command (%s)", 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)); + LOGE("Error processing uevent msg (%s)", strerror(errno)); } } - - } // while } @@ -224,7 +208,7 @@ int send_msg(char* message) pthread_mutex_lock(&write_mutex); - LOG_VOL("send_msg(%s):\n", message); +// LOG_VOL("send_msg(%s):", message); if (fw_sock >= 0) result = write(fw_sock, message, strlen(message) + 1); @@ -240,7 +224,7 @@ int send_msg_with_data(char *message, char *data) char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1); if (!buffer) { - LOGE("alloca failed in send_msg_with_data\n"); + LOGE("alloca failed in send_msg_with_data"); return -1; } diff --git a/vold/vold.h b/vold/vold.h index f25fcff..0876bec 100644 --- a/vold/vold.h +++ b/vold/vold.h @@ -86,6 +86,8 @@ int ums_bootstrap(void); int volmgr_bootstrap(void); +int switch_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); diff --git a/vold/volmgr.c b/vold/volmgr.c index b162ff5..7c4c077 100644 --- a/vold/volmgr.c +++ b/vold/volmgr.c @@ -31,18 +31,21 @@ #include "volmgr.h" #include "blkdev.h" #include "ums.h" +#include "format.h" +#include "devmapper.h" #include "volmgr_ext3.h" #include "volmgr_vfat.h" #define DEBUG_VOLMGR 0 -static volume_t *vol_root = NULL; +static volume_t *vol_root = NULL; +static boolean safe_mode = true; 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 } + { "ext3", ext_identify, ext_check, ext_mount , true }, + { "vfat", vfat_identify, vfat_check, vfat_mount , false }, + { NULL, NULL, NULL, NULL , false} }; struct _volume_state_event_map { @@ -80,26 +83,163 @@ 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, void *arg); static int _volmgr_enable_ums(volume_t *); -static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *arg)); -static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, int emit_statechange); +static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *arg), boolean emit_statechange); +static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean 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_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg); static void volmgr_reaper_thread_sighandler(int signo); +static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path); +static int volmgr_send_eject_request(volume_t *v); +static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked); + +static boolean _mountpoint_mounted(char *mp) +{ + char device[256]; + char mount_path[256]; + char rest[256]; + FILE *fp; + char line[1024]; + + if (!(fp = fopen("/proc/mounts", "r"))) { + LOGE("Error opening /proc/mounts (%s)", strerror(errno)); + return false; + } + + while(fgets(line, sizeof(line), fp)) { + line[strlen(line)-1] = '\0'; + sscanf(line, "%255s %255s %255s\n", device, mount_path, rest); + if (!strcmp(mount_path, mp)) { + fclose(fp); + return true; + } + + } + + fclose(fp); + return false; +} /* * Public functions */ + +int volmgr_set_volume_key(char *mount_point, unsigned char *key) +{ + volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true); + + if (!v) + return -ENOENT; + + if (v->media_type != media_devmapper) { + LOGE("Cannot set key on a non devmapper volume"); + pthread_mutex_unlock(&v->lock); + return -EINVAL; + } + + memcpy(v->dm->key, key, sizeof(v->dm->key)); + pthread_mutex_unlock(&v->lock); + return 0; +} + +int volmgr_format_volume(char *mount_point) +{ + int rc; + volume_t *v; + + LOG_VOL("volmgr_format_volume(%s):", mount_point); + + v = volmgr_lookup_volume_by_mountpoint(mount_point, true); + + if (!v) + return -ENOENT; + + if (v->state == volstate_mounted || + v->state == volstate_mounted_ro || + v->state == volstate_ums || + v->state == volstate_checking) { + LOGE("Can't format '%s', currently in state %d", mount_point, v->state); + pthread_mutex_unlock(&v->lock); + return -EBUSY; + } else if (v->state == volstate_nomedia && + v->media_type != media_devmapper) { + LOGE("Can't format '%s', (no media)", mount_point); + pthread_mutex_unlock(&v->lock); + return -ENOMEDIUM; + } + + // XXX:Reject if the underlying source media is not present + + if (v->media_type == media_devmapper) { + if ((rc = devmapper_genesis(v->dm)) < 0) { + LOGE("devmapper genesis failed for %s (%d)", mount_point, rc); + pthread_mutex_unlock(&v->lock); + return rc; + } + } else { + if ((rc = initialize_mbr(v->dev->disk)) < 0) { + LOGE("MBR init failed for %s (%d)", mount_point, rc); + pthread_mutex_unlock(&v->lock); + return rc; + } + } + + volume_setstate(v, volstate_formatting); + pthread_mutex_unlock(&v->lock); + return rc; +} + int volmgr_bootstrap(void) { int rc; if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) { - LOGE("Unable to process config\n"); + LOGE("Unable to process config"); return rc; } + /* + * Check to see if any of our volumes is mounted + */ + volume_t *v = vol_root; + while (v) { + if (_mountpoint_mounted(v->mount_point)) { + LOGW("Volume '%s' already mounted at startup", v->mount_point); + v->state = volstate_mounted; + } + v = v->next; + } + + return 0; +} + +int volmgr_safe_mode(boolean enable) +{ + if (enable == safe_mode) + return 0; + + safe_mode = enable; + + volume_t *v = vol_root; + int rc; + + while (v) { + pthread_mutex_lock(&v->lock); + if (v->state == volstate_mounted && v->fs) { + rc = v->fs->mount_fn(v->dev, v, safe_mode); + if (!rc) { + LOGI("Safe mode %s on %s", (enable ? "enabled" : "disabled"), v->mount_point); + } else { + LOGE("Failed to %s safe-mode on %s (%s)", + (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc)); + } + } + + pthread_mutex_unlock(&v->lock); + v = v->next; + } + return 0; } @@ -111,10 +251,11 @@ int volmgr_send_states(void) 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); + LOGE("Error sending state to framework (%d)", rc); } pthread_mutex_unlock(&vol_scan->lock); vol_scan = vol_scan->next; + break; // XXX: } return 0; @@ -128,67 +269,94 @@ 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); + if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true))) return 0; - } pthread_mutex_lock(&vol->lock); + + if (vol->state == volstate_mounted) { + LOGE("Volume %s already mounted (did we just crash?)", vol->mount_point); + pthread_mutex_unlock(&vol->lock); + return 0; + } + 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; +{ + volume_t *v; - 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; - } + v = volmgr_lookup_volume_by_mountpoint(mount_point, true); + if (!v) + return -ENOENT; - if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) { - LOGE("volmgr failed to start volume '%s'\n", v->mount_point); - } + if (v->media_type == media_devmapper) { + if (devmapper_start(v->dm) < 0) { + LOGE("volmgr failed to start devmapper volume '%s'", + v->mount_point); + } + } else if (v->media_type == media_mmc) { + if (!v->dev) { + LOGE("Cannot start volume '%s' (volume is not bound)", mount_point); pthread_mutex_unlock(&v->lock); - return 0; + return -ENOENT; + } + + if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) { + LOGE("volmgr failed to start volume '%s'", v->mount_point); } - v = v->next; } - return -ENOENT; + pthread_mutex_unlock(&v->lock); + return 0; +} + +static void _cb_volstopped_for_devmapper_teardown(volume_t *v, void *arg) +{ + devmapper_stop(v->dm); + volume_setstate(v, volstate_nomedia); + pthread_mutex_unlock(&v->lock); } int volmgr_stop_volume_by_mountpoint(char *mount_point) { - volume_t *v = vol_root; + int rc; + volume_t *v; - while(v) { - if (!strcmp(v->mount_point, mount_point)) { - pthread_mutex_lock(&v->lock); - if (volmgr_shutdown_volume(v, NULL) < 0) - LOGE("unable to shutdown volume '%s'\n", v->mount_point); - pthread_mutex_unlock(&v->lock); - return 0; - } - v = v->next; - } + v = volmgr_lookup_volume_by_mountpoint(mount_point, true); + if (!v) + return -ENOENT; + + if (v->state == volstate_mounted) + volmgr_send_eject_request(v); - return -ENOENT; + if (v->media_type == media_devmapper) + rc = volmgr_shutdown_volume(v, _cb_volstopped_for_devmapper_teardown, false); + else + rc = volmgr_shutdown_volume(v, NULL, true); + + /* + * If shutdown returns -EINPROGRESS, + * do *not* release the lock as + * it is now owned by the reaper thread + */ + if (rc != -EINPROGRESS) { + if (rc) + LOGE("unable to shutdown volume '%s'", v->mount_point); + pthread_mutex_unlock(&v->lock); + } + return 0; } 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 + LOG_VOL("Volmgr notified of %d:%d eject", dev->major, dev->minor); volume_t *v; + int rc; // XXX: Partitioning support is going to need us to stop *all* // devices in this volume @@ -199,21 +367,80 @@ int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *)) } pthread_mutex_lock(&v->lock); - if (v->state == volstate_mounted) + + volume_state_t old_state = v->state; + + if (v->state == volstate_mounted || + v->state == volstate_ums || + v->state == volstate_checking) { + volume_setstate(v, volstate_badremoval); - int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false); + /* + * Stop any devmapper volumes which + * are using us as a source + * XXX: We may need to enforce stricter + * order here + */ + volume_t *dmvol = vol_root; + while (dmvol) { + if ((dmvol->media_type == media_devmapper) && + (dmvol->dm->src_type == dmsrc_loopback) && + (!strncmp(dmvol->dm->type_data.loop.loop_src, + v->mount_point, strlen(v->mount_point)))) { + + pthread_mutex_lock(&dmvol->lock); + if (dmvol->state != volstate_nomedia) { + rc = volmgr_shutdown_volume(dmvol, _cb_volstopped_for_devmapper_teardown, false); + if (rc != -EINPROGRESS) { + if (rc) + LOGE("unable to shutdown volume '%s'", v->mount_point); + pthread_mutex_unlock(&dmvol->lock); + } + } else + pthread_mutex_unlock(&dmvol->lock); + } + dmvol = dmvol->next; + } - pthread_mutex_unlock(&v->lock); - return rc; + } else if (v->state == volstate_formatting) { + /* + * The device is being ejected due to + * kernel disk revalidation. + */ + LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)", + dev->major, dev->minor); + if (cb) + cb(dev); + pthread_mutex_unlock(&v->lock); + return 0; + } else + volume_setstate(v, volstate_nomedia); + + if (old_state == volstate_ums) { + ums_disable(v->ums_path); + pthread_mutex_unlock(&v->lock); + } else { + int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false); + if (rc != -EINPROGRESS) { + if (rc) + LOGE("unable to shutdown volume '%s'", v->mount_point); + pthread_mutex_unlock(&v->lock); + } + } + return 0; } 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); +#if DEBUG_VOLMGR + LOG_VOL("Volume %s has been stopped for eject", v->mount_point); +#endif + + if (eject_cb) + eject_cb(v->dev); v->dev = NULL; // Clear dev because its being ejected } @@ -231,27 +458,45 @@ int volmgr_enable_ums(boolean enable) if (enable) { pthread_mutex_lock(&v->lock); + if (v->state == volstate_mounted) + volmgr_send_eject_request(v); + else if (v->state == volstate_ums) { + pthread_mutex_unlock(&v->lock); + goto next_vol; + } + // 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); + rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false); + if (rc != -EINPROGRESS) { + if (rc) + LOGE("unable to shutdown volume '%s'", v->mount_point); + pthread_mutex_unlock(&v->lock); + } } else { // Disable UMS pthread_mutex_lock(&v->lock); + if (v->state != volstate_ums) { + pthread_mutex_unlock(&v->lock); + goto next_vol; + } + if ((rc = ums_disable(v->ums_path)) < 0) { - LOGE("unable to disable ums on '%s'\n", v->mount_point); + LOGE("unable to disable ums on '%s'", 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); + LOG_VOL("Kick-starting volume %d:%d after UMS disable", + v->dev->disk->major, v->dev->disk->minor); // 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); + LOGE("volmgr failed to consider disk %d:%d", + v->dev->disk->major, v->dev->disk->minor); } pthread_mutex_unlock(&v->lock); } } + next_vol: v = v->next; } return 0; @@ -261,30 +506,63 @@ int volmgr_enable_ums(boolean enable) * Static functions */ +static int volmgr_send_eject_request(volume_t *v) +{ + return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point); +} + // 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); + LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):", vol->mount_point, + dev->major, dev->minor); #endif - if (vol->state != volstate_nomedia && - vol->state != volstate_unmounted && - vol->state != volstate_badremoval) { - LOGE("Volume manager is already handling volume '%s' (currently in state %d)\n", vol->mount_point, vol->state); + if (vol->state == volstate_unknown || + vol->state == volstate_mounted || + vol->state == volstate_mounted_ro || + vol->state == volstate_damaged) { + LOGE("Cannot consider volume '%s' because it is in state '%d", + vol->mount_point, vol->state); return -EADDRINUSE; } - volume_setstate(vol, volstate_unmounted); + if (vol->state == volstate_formatting) { + LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'", + dev->devpath, vol->mount_point); + /* + * Since we only support creating 1 partition (right now), + * we can just lookup the target by devno + */ + blkdev_t *part = blkdev_lookup_by_devno(dev->major, 1); + if (!part) { + part = blkdev_lookup_by_devno(dev->major, 0); + if (!part) { + LOGE("Unable to find device to format"); + return -ENODEV; + } + } + + if ((rc = format_partition(part, + vol->media_type == media_devmapper ? + FORMAT_TYPE_EXT2 : FORMAT_TYPE_FAT32)) < 0) { + LOGE("format failed (%d)", rc); + return rc; + } + + } - LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'\n", dev->devpath, vol->mount_point); + LOGI("Evaluating dev '%s' for mountable filesystems for '%s'", + 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); + LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", vol->mount_point, + dev->major, dev->minor, rc); #endif } else { /* @@ -298,12 +576,13 @@ static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev) 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)); + LOGE("Error - unable to lookup partition for blkdev %d:%d", 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); + LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", + vol->mount_point, part->major, part->minor, rc); #endif if (!rc) break; @@ -311,13 +590,14 @@ static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev) if (rc == -ENODEV) { // Assert to make sure each partition had a backing blkdev - LOGE("Internal consistency error\n"); + LOGE("Internal consistency error"); return 0; } } if (rc == -ENODATA) { - LOGE("Device %s contains no usable filesystems\n", dev->dev_fspath); + LOGE("Device %d:%d contains no usable filesystems", + dev->major, dev->minor); rc = 0; } @@ -326,14 +606,15 @@ static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev) static void volmgr_reaper_thread_sighandler(int signo) { - LOGE("volmgr reaper thread got signal %d\n", signo); + LOGE("Volume reaper thread got signal %d", signo); } static void __reaper_cleanup(void *arg) { volume_t *vol = (volume_t *) arg; - LOG_VOL("__reaper_cleanup(%s):\n", vol->mount_point); + if (vol->worker_args.reaper_args.cb) + vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg); vol->worker_running = false; @@ -349,7 +630,6 @@ 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(); @@ -362,32 +642,36 @@ static void *volmgr_reaper_thread(void *arg) actions.sa_handler = volmgr_reaper_thread_sighandler; sigaction(SIGUSR1, &actions, NULL); - LOG_VOL("Worker thread pid %d reaping %s\n", getpid(), vol->mount_point); + LOGW("Reaper here - working on %s", vol->mount_point); boolean send_sig_kill = false; int i, rc; for (i = 0; i < 10; i++) { + errno = 0; rc = umount(vol->mount_point); - LOG_VOL("volmngr reaper umount(%s) attempt %d rc = %d\n", - vol->mount_point, i + 1, rc); + LOGW("volmngr reaper umount(%s) attempt %d (%s)", + vol->mount_point, i + 1, strerror(errno)); 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 (i >= 4) { + KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0); + if (!send_sig_kill) + send_sig_kill = true; + } } if (!rc) { - LOG_VOL("Reaper sucessfully unmounted %s\n", vol->mount_point); + LOGI("Reaper sucessfully unmounted %s", vol->mount_point); + vol->fs = NULL; volume_setstate(vol, volstate_unmounted); } else { - LOGE("Unable to unmount!! (%d)\n", rc); + LOGE("Unable to unmount!! (%d)", rc); } out: @@ -396,16 +680,18 @@ static void *volmgr_reaper_thread(void *arg) return NULL; } -static void volmgr_uncage_reaper(volume_t *vol) +// vol->lock must be held! +static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg) { + if (vol->worker_running) { - LOGE("Worker thread is currently running.. waiting..\n"); + LOGE("Worker thread is currently running.. waiting.."); pthread_mutex_lock(&vol->worker_sem); - LOG_VOL("Worker thread now available\n"); + LOGI("Worker thread now available"); } - vol->worker_args.fs = NULL; - vol->worker_args.dev = NULL; + vol->worker_args.reaper_args.cb = cb; + vol->worker_args.reaper_args.cb_arg = arg; pthread_attr_t attr; pthread_attr_init(&attr); @@ -422,22 +708,29 @@ static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void // 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(); + + LOGI("volmngr quick stop umount(%s) attempt %d (%s)", + v->mount_point, i + 1, strerror(errno)); + + if (i == 0) + usleep(1000 * 250); // First failure, sleep for 250 ms + else + sched_yield(); } if (!rc) { - LOG_VOL("volmgr_stop_volume(%s): Volume unmounted sucessfully\n", + LOGI("volmgr_stop_volume(%s): Volume unmounted sucessfully", v->mount_point); if (emit_statechange) volume_setstate(v, volstate_unmounted); + v->fs = NULL; goto out_cb_immed; } @@ -445,21 +738,19 @@ static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void * 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); + LOGW("Volume %s is busy (%d) - uncaging the reaper", v->mount_point, rc); + volmgr_uncage_reaper(v, cb, arg); return -EINPROGRESS; } else if (v->state == volstate_checking) { volume_setstate(v, volstate_unmounted); if (v->worker_running) { - LOG_VOL("Cancelling worker thread\n"); + LOG_VOL("Cancelling worker thread"); pthread_kill(v->worker_thread, SIGUSR1); } else - LOGE("Strange... we were in checking state but worker thread wasn't running..\n"); + LOGE("Strange... we were in checking state but worker thread wasn't running.."); 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); @@ -469,32 +760,45 @@ static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void /* * Gracefully stop a volume + * v->lock must be held! + * if we return -EINPROGRESS, do NOT release the lock as the reaper + * is using the volume */ -static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *)) +static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *), boolean emit_statechange) { - return volmgr_stop_volume(v, cb, NULL, true); + return volmgr_stop_volume(v, cb, NULL, emit_statechange); } 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); +#if DEBUG_VOLMGR + LOG_VOL("Volume %s has been stopped for shutdown", v->mount_point); +#endif shutdown_cb(v); } + /* * Called when a volume is sucessfully unmounted for UMS enable */ static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg) { int rc; + char *devdir_path; + +#if DEBUG_VOLMGR + LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point); +#endif + devdir_path = blkdev_get_devpath(v->dev->disk); - LOG_VOL("_cb_volstopped_for_ums_enable(%s):\n", v->dev->dev_fspath); - if ((rc = ums_enable(v->dev->disk->dev_fspath, v->ums_path)) < 0) { - LOGE("Error enabling ums (%d)\n", rc); + if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) { + free(devdir_path); + LOGE("Error enabling ums (%d)", rc); return; } + free(devdir_path); volume_setstate(v, volstate_ums); pthread_mutex_unlock(&v->lock); } @@ -508,20 +812,43 @@ static int volmgr_readconfig(char *cfg_path) node = root->first_child; while (node) { - if (!strcmp(node->name, "volume")) + if (!strncmp(node->name, "volume_", 7)) volmgr_config_volume(node); else - LOGE("Skipping unknown configuration node '%s'\n", node->name); + LOGE("Skipping unknown configuration node '%s'", node->name); node = node->next; } return 0; } +static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path) +{ + int i; + +#if DEBUG_VOLMGR + LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):", v, media_path); +#endif + for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) { + if (!v->media_paths[i]) { + v->media_paths[i] = strdup(media_path); + return; + } + } + LOGE("Unable to add media path '%s' to volume (out of media slots)", media_path); +} + static int volmgr_config_volume(cnode *node) { volume_t *new; - int rc = 0; + int rc = 0, i; + + char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs; + uint32_t dm_size_mb = 0; + dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL; +#if DEBUG_VOLMGR + LOG_VOL("volmgr_configure_volume(%s):", node->name); +#endif if (!(new = malloc(sizeof(volume_t)))) return -ENOMEM; memset(new, 0, sizeof(volume_t)); @@ -534,12 +861,16 @@ static int volmgr_config_volume(cnode *node) while (child) { if (!strcmp(child->name, "media_path")) - new->media_path = strdup(child->value); + volmgr_add_mediapath_to_volume(new, child->value); + else if (!strcmp(child->name, "emu_media_path")) + volmgr_add_mediapath_to_volume(new, child->value); else if (!strcmp(child->name, "media_type")) { if (!strcmp(child->value, "mmc")) new->media_type = media_mmc; + else if (!strcmp(child->value, "devmapper")) + new->media_type = media_devmapper; else { - LOGE("Invalid media type '%s'\n", child->value); + LOGE("Invalid media type '%s'", child->value); rc = -EINVAL; goto out_free; } @@ -547,15 +878,45 @@ static int volmgr_config_volume(cnode *node) new->mount_point = strdup(child->value); else if (!strcmp(child->name, "ums_path")) new->ums_path = strdup(child->value); + else if (!strcmp(child->name, "dm_src")) + dm_src = strdup(child->value); + else if (!strcmp(child->name, "dm_src_type")) + dm_src_type = strdup(child->value); + else if (!strcmp(child->name, "dm_src_size_mb")) + dm_size_mb = atoi(child->value); + else if (!strcmp(child->name, "dm_target")) + dm_tgt = strdup(child->value); + else if (!strcmp(child->name, "dm_target_params")) + dm_param = strdup(child->value); + else if (!strcmp(child->name, "dm_target_fs")) + dm_tgtfs = strdup(child->value); else - LOGE("Ignoring unknown config entry '%s'\n", child->name); + LOGE("Ignoring unknown config entry '%s'", 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 (new->media_type == media_mmc) { + if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) { + LOGE("Required configuration parameter missing for mmc volume"); + rc = -EINVAL; + goto out_free; + } + } else if (new->media_type == media_devmapper) { + if (!dm_src || !dm_src_type || !dm_tgt || + !dm_param || !dm_tgtfs || !dm_size_mb) { + LOGE("Required configuration parameter missing for devmapper volume"); + rc = -EINVAL; + goto out_free; + } + + char dm_mediapath[255]; + if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb, + dm_tgt, dm_param, dm_tgtfs, dm_mediapath))) { + LOGE("Unable to initialize devmapping"); + goto out_free; + } + LOG_VOL("media path for devmapper volume = '%s'", dm_mediapath); + volmgr_add_mediapath_to_volume(new, dm_mediapath); } if (!vol_root) @@ -567,11 +928,37 @@ static int volmgr_config_volume(cnode *node) scan->next = new; } + if (dm_src) + free(dm_src); + if (dm_src_type) + free(dm_src_type); + if (dm_tgt) + free(dm_tgt); + if (dm_param) + free(dm_param); + if (dm_tgtfs) + free(dm_tgtfs); + return rc; out_free: - if (new->media_path) - free(new->media_path); + + if (dm_src) + free(dm_src); + if (dm_src_type) + free(dm_src_type); + if (dm_tgt) + free(dm_tgt); + if (dm_param) + free(dm_param); + if (dm_tgtfs) + free(dm_tgtfs); + + + for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) { + if (new->media_paths[i]) + free(new->media_paths[i]); + } if (new->mount_point) free(new->mount_point); if (new->ums_path) @@ -590,27 +977,43 @@ static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev) return NULL; } +static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked) +{ + volume_t *v = vol_root; + + while(v) { + pthread_mutex_lock(&v->lock); + if (!strcmp(v->mount_point, mount_point)) { + if (!leave_locked) + pthread_mutex_unlock(&v->lock); + return v; + } + pthread_mutex_unlock(&v->lock); + v = v->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; + int i; 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; + + for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) { + if (!scan->media_paths[i]) + continue; + + if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i]))) + return scan; + else if (!fuzzy && !strcmp(media_path, scan->media_paths[i])) + return scan; + } scan = scan->next; } - return res; + return NULL; } /* @@ -625,16 +1028,22 @@ static int _volmgr_start(volume_t *vol, blkdev_t *dev) int rc = ENODATA; #if DEBUG_VOLMGR - LOG_VOL("_volmgr_start(%s, %s):\n", vol->mount_point, dev->dev_fspath); + LOG_VOL("_volmgr_start(%s, %d:%d):", vol->mount_point, + dev->major, dev->minor); #endif + if (vol->state == volstate_mounted) { + LOGE("Unable to start volume '%s' (already mounted)", vol->mount_point); + return -EBUSY; + } + 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); + LOGE("No supported filesystems on %d:%d", dev->major, dev->minor); volume_setstate(vol, volstate_nofs); return -ENODATA; } @@ -650,15 +1059,15 @@ static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkde */ if (vol->worker_running) { - LOGE("Worker thread is currently running.. waiting..\n"); + LOGE("Worker thread is currently running.. waiting.."); pthread_mutex_lock(&vol->worker_sem); - LOG_VOL("Worker thread now available\n"); + LOGI("Worker thread now available"); } vol->dev = dev; - vol->worker_args.fs = fs; - vol->worker_args.dev = dev; + vol->worker_args.start_args.fs = fs; + vol->worker_args.start_args.dev = dev; pthread_attr_t attr; pthread_attr_init(&attr); @@ -673,7 +1082,9 @@ 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); +#if DEBUG_VOLMGR + LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point); +#endif vol->worker_running = false; @@ -702,38 +1113,56 @@ static void *volmgr_start_fs_thread(void *arg) 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; + struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs; + blkdev_t *dev = vol->worker_args.start_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 DEBUG_VOLMGR + LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s", getpid(), + fs->name, dev->major, dev->minor, vol->mount_point); +#endif if (fs->check_fn) { - LOG_VOL("Starting %s filesystem check on %s\n", fs->name, dev->dev_fspath); +#if DEBUG_VOLMGR + LOG_VOL("Starting %s filesystem check on %d:%d", fs->name, + dev->major, dev->minor); +#endif 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"); + LOGE("filesystem check aborted"); goto out; } if (rc < 0) { - LOG_VOL("%s filesystem check failed on %s\n", fs->name, dev->dev_fspath); + LOGE("%s filesystem check failed on %d:%d (%s)", fs->name, + dev->major, dev->minor, strerror(-rc)); + if (rc == -ENODATA) { + volume_setstate(vol, volstate_nofs); + goto out; + } goto out_unmountable; } - LOG_VOL("%s filesystem check of %s OK\n", fs->name, dev->dev_fspath); +#if DEBUG_VOLMGR + LOGI("%s filesystem check of %d:%d OK", fs->name, + dev->major, dev->minor); +#endif } - rc = fs->mount_fn(dev, vol); + rc = fs->mount_fn(dev, vol, safe_mode); if (!rc) { - LOG_VOL("Sucessfully mounted %s filesystem %s on %s\n", fs->name, dev->devpath, vol->mount_point); + LOGI("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)", + fs->name, dev->major, dev->minor, vol->mount_point, + (safe_mode ? "on" : "off")); + vol->fs = fs; volume_setstate(vol, volstate_mounted); goto out; } - LOGE("%s filesystem mount of %s failed (%d)\n", fs->name, dev->devpath, rc); + LOGE("%s filesystem mount of %d:%d failed (%d)", fs->name, dev->major, + dev->minor, rc); out_unmountable: volume_setstate(vol, volstate_damaged); @@ -745,19 +1174,26 @@ static void *volmgr_start_fs_thread(void *arg) static void volmgr_start_fs_thread_sighandler(int signo) { - LOGE("volmgr thread got signal %d\n", signo); + LOGE("Volume startup thread got signal %d", 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); + if (state == vol->state) + return; + +#if DEBUG_VOLMGR + LOG_VOL("Volume %s state change from %d -> %d", vol->mount_point, vol->state, state); +#endif vol->state = state; char *prop_val = conv_volstate_to_propstr(vol->state); - property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val); - volume_send_state(vol); + if (prop_val) { + property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val); + volume_send_state(vol); + } } static int volume_send_state(volume_t *vol) @@ -776,8 +1212,6 @@ static char *conv_volstate_to_eventstr(volume_state_t state) break; } - if (!volume_state_strings[i].event) - LOGE("conv_volstate_to_eventstr(%d): Invalid state\n", state); return volume_state_strings[i].event; } @@ -790,8 +1224,6 @@ static char *conv_volstate_to_propstr(volume_state_t 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; } diff --git a/vold/volmgr.h b/vold/volmgr.h index a7f5701..2c7ec50 100644 --- a/vold/volmgr.h +++ b/vold/volmgr.h @@ -23,6 +23,7 @@ #include "vold.h" #include "blkdev.h" #include "media.h" +#include "devmapper.h" #define PROP_EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE" @@ -70,15 +71,18 @@ typedef enum volume_state { volstate_ejecting, #define VOLD_EVT_EJECTING "volume_ejecting:" #define VOLD_ES_PVAL_EJECTING "ejecting" + + volstate_formatting, } 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); + int (*identify_fn) (blkdev_t *dev); + int (*check_fn) (blkdev_t *dev); + int (*mount_fn) (blkdev_t *dev, struct volume *vol, boolean safe_mode); + boolean case_sensitive_paths; }; struct volmgr_start_args { @@ -86,21 +90,35 @@ struct volmgr_start_args { blkdev_t *dev; }; +struct volmgr_reaper_args { + void (*cb) (struct volume *, void *); + void *cb_arg; +}; + +#define VOLMGR_MAX_MEDIAPATHS_PER_VOLUME 8 + typedef struct volume { - char *media_path; - media_type_t media_type; - char *mount_point; - char *ums_path; + char *media_paths[VOLMGR_MAX_MEDIAPATHS_PER_VOLUME]; + + media_type_t media_type; + char *mount_point; + char *ums_path; + struct devmapping *dm; 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; + union { + struct volmgr_start_args start_args; + struct volmgr_reaper_args reaper_args; + } worker_args; boolean worker_running; pthread_mutex_t worker_sem; + struct volmgr_fstable_entry *fs; + struct volume *next; } volume_t; @@ -110,6 +128,8 @@ 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); - +int volmgr_safe_mode(boolean enable); +int volmgr_format_volume(char *mount_point); +int volmgr_set_volume_key(char *mount_point, unsigned char *key); void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded); #endif diff --git a/vold/volmgr_ext3.c b/vold/volmgr_ext3.c index 2be07fb..680be21 100644 --- a/vold/volmgr_ext3.c +++ b/vold/volmgr_ext3.c @@ -15,34 +15,170 @@ * limitations under the License. */ +#include <fcntl.h> #include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mount.h> + +#include <linux/ext2_fs.h> +#include <linux/ext3_fs.h> + #include "vold.h" #include "volmgr.h" #include "volmgr_ext3.h" +#include "logwrapper.h" + + +#define EXT_DEBUG 0 -#define EXT3_DEBUG 0 +static char E2FSCK_PATH[] = "/system/bin/e2fsck"; -int ext3_identify(blkdev_t *dev) +int ext_identify(blkdev_t *dev) { -#if EXT3_DEBUG - LOG_VOL("ext3_identify(%s):\n", dev->dev_fspath); + int rc = -1; + int fd; + struct ext3_super_block sb; + char *devpath; + +#if EXT_DEBUG + LOG_VOL("ext_identify(%d:%d):", dev-major, dev->minor); +#endif + + devpath = blkdev_get_devpath(dev); + + if ((fd = open(devpath, O_RDWR)) < 0) { + LOGE("Unable to open device '%s' (%s)", devpath, + strerror(errno)); + free(devpath); + return -errno; + } + + if (lseek(fd, 1024, SEEK_SET) < 0) { + LOGE("Unable to lseek to get superblock (%s)", strerror(errno)); + rc = -errno; + goto out; + } + + if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { + LOGE("Unable to read superblock (%s)", strerror(errno)); + rc = -errno; + goto out; + } + + if (sb.s_magic == EXT2_SUPER_MAGIC || + sb.s_magic == EXT3_SUPER_MAGIC) + rc = 0; + else + rc = -ENODATA; + + out: +#if EXT_DEBUG + LOG_VOL("ext_identify(%s): rc = %d", devpath, rc); #endif - return -ENOSYS; + free(devpath); + close(fd); + return rc; } -int ext3_check(blkdev_t *dev) +int ext_check(blkdev_t *dev) { -#if EXT3_DEBUG - LOG_VOL("ext3_check(%s):\n", dev->dev_fspath); + char *devpath; + +#if EXT_DEBUG + LOG_VOL("ext_check(%s):", dev->dev_fspath); #endif - return -ENOSYS; + + devpath = blkdev_get_devpath(dev); + + if (access(E2FSCK_PATH, X_OK)) { + LOGE("ext_check(%s): %s not found (skipping checks)", + devpath, E2FSCK_PATH); + free(devpath); + return 0; + } + + char *args[5]; + + args[0] = E2FSCK_PATH; + args[1] = "-v"; + args[2] = "-p"; + args[3] = devpath; + args[4] = NULL; + + int rc = logwrap(4, args); + + if (rc == 0) { + LOG_VOL("filesystem '%s' had no errors", devpath); + } else if (rc == 1) { + LOG_VOL("filesystem '%s' had corrected errors", devpath); + rc = 0; + } else if (rc == 2) { + LOGE("VOL volume '%s' had corrected errors (system should be rebooted)", devpath); + rc = -EIO; + } else if (rc == 4) { + LOGE("VOL volume '%s' had uncorrectable errors", devpath); + rc = -EIO; + } else if (rc == 8) { + LOGE("Operational error while checking volume '%s'", devpath); + rc = -EIO; + } else { + LOGE("Unknown e2fsck exit code (%d)", rc); + rc = -EIO; + } + free(devpath); + return rc; } -int ext3_mount(blkdev_t *dev, volume_t *vol) +int ext_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) { -#if EXT3_DEBUG - LOG_VOL("ext3_mount(%s, %s):\n", dev->dev_fspath, vol->mount_point); +#if EXT_DEBUG + LOG_VOL("ext_mount(%s, %s, %d):", dev->dev_fspath, vol->mount_point, safe_mode); #endif - return -ENOSYS; + + char *fs[] = { "ext3", "ext2", NULL }; + char *devpath; + + devpath = blkdev_get_devpath(dev); + + int flags, rc = 0; + + flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME; + + if (safe_mode) + flags |= MS_SYNCHRONOUS; + + if (vol->state == volstate_mounted) { + LOG_VOL("Remounting %s on %s, safe mode %d", devpath, + vol->mount_point, safe_mode); + flags |= MS_REMOUNT; + } + + char **f; + for (f = fs; *f != NULL; f++) { + rc = mount(devpath, vol->mount_point, *f, flags, NULL); + if (rc && errno == EROFS) { + LOGE("ext_mount(%s, %s): Read only filesystem - retrying mount RO", + devpath, vol->mount_point); + flags |= MS_RDONLY; + rc = mount(devpath, vol->mount_point, *f, flags, NULL); + } +#if EXT_DEBUG + LOG_VOL("ext_mount(%s, %s): %s mount rc = %d", devpath, *f, + vol->mount_point, rc); +#endif + if (!rc) + break; + } + free(devpath); + + // Chmod the mount point so that its a free-for-all. + // (required for consistency with VFAT.. sigh) + if (chmod(vol->mount_point, 0777) < 0) { + LOGE("Failed to chmod %s (%s)", vol->mount_point, strerror(errno)); + return -errno; + } + + return rc; } diff --git a/vold/volmgr_ext3.h b/vold/volmgr_ext3.h index a8bac19..bfe882a 100644 --- a/vold/volmgr_ext3.h +++ b/vold/volmgr_ext3.h @@ -21,9 +21,7 @@ #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); +int ext_identify(blkdev_t *blkdev); +int ext_check(blkdev_t *blkdev); +int ext_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode); #endif diff --git a/vold/volmgr_vfat.c b/vold/volmgr_vfat.c index 661f714..344a166 100644 --- a/vold/volmgr_vfat.c +++ b/vold/volmgr_vfat.c @@ -31,7 +31,7 @@ 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); + LOG_VOL("vfat_identify(%d:%d):", dev->major, dev->minor); #endif return 0; // XXX: Implement } @@ -41,12 +41,12 @@ int vfat_check(blkdev_t *dev) int rc; #if VFAT_DEBUG - LOG_VOL("vfat_check(%s):\n", dev->dev_fspath); + LOG_VOL("vfat_check(%d:%d):", dev->major, dev->minor); #endif if (access(FSCK_MSDOS_PATH, X_OK)) { - LOGE("vfat_check(%s): %s not found (skipping checks)\n", - FSCK_MSDOS_PATH, dev->dev_fspath); + LOGE("vfat_check(%d:%d): %s not found (skipping checks)", + dev->major, dev->minor, FSCK_MSDOS_PATH); return 0; } @@ -57,61 +57,77 @@ int vfat_check(blkdev_t *dev) args[2] = "-V"; args[3] = "-w"; args[4] = "-p"; - args[5] = dev->dev_fspath; + args[5] = blkdev_get_devpath(dev); args[6] = NULL; rc = logwrap(6, args); + free(args[5]); #else char *args[6]; args[0] = FSCK_MSDOS_PATH; args[1] = "-v"; args[2] = "-w"; args[3] = "-p"; - args[4] = dev->dev_fspath; + args[4] = blkdev_get_devpath(dev); args[5] = NULL; rc = logwrap(5, args); + free(args[4]); #endif if (rc == 0) { - LOG_VOL("Filesystem check completed OK\n"); + LOG_VOL("Filesystem check completed OK"); return 0; } else if (rc == 1) { - LOG_VOL("Filesystem check failed (general failure)\n"); + LOG_VOL("Filesystem check failed (general failure)"); return -EINVAL; } else if (rc == 2) { - LOG_VOL("Filesystem check failed (invalid usage)\n"); + LOG_VOL("Filesystem check failed (invalid usage)"); return -EIO; } else if (rc == 4) { - LOG_VOL("Filesystem check completed (errors fixed)\n"); + LOG_VOL("Filesystem check completed (errors fixed)"); + } else if (rc == 8) { + LOG_VOL("Filesystem check failed (not a FAT filesystem)"); + return -ENODATA; } else { - LOG_VOL("Filesystem check failed (unknown exit code %d)\n", rc); + LOG_VOL("Filesystem check failed (unknown exit code %d)", rc); return -EIO; } return 0; } -int vfat_mount(blkdev_t *dev, volume_t *vol) +int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) { int flags, rc; + char *devpath; + + devpath = blkdev_get_devpath(dev); #if VFAT_DEBUG - LOG_VOL("vfat_mount(%s, %s):\n", dev->dev_fspath, vol->mount_point); + LOG_VOL("vfat_mount(%d:%d, %s, %d):", dev->major, dev->minor, vol->mount_point, safe_mode); #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 (vol->state == volstate_mounted) { + LOG_VOL("Remounting %d:%d on %s, safe mode %d", dev->major, + dev->minor, vol->mount_point, safe_mode); + flags |= MS_REMOUNT; + } + + rc = mount(devpath, vol->mount_point, "vfat", flags, + "utf8,uid=1000,gid=1000,fmask=711,dmask=700,shortname=mixed"); if (rc && errno == EROFS) { - LOGE("vfat_mount(%s, %s): Read only filesystem - retrying mount RO\n", - dev->dev_fspath, vol->mount_point); + LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO", + dev->major, dev->minor, 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"); + rc = mount(devpath, vol->mount_point, "vfat", flags, + "utf8,uid=1000,gid=1000,fmask=711,dmask=700,shortname=mixed"); } #if VFAT_DEBUG - LOG_VOL("vfat_mount(%s, %s): mount rc = %d\n", dev->dev_fspath, + LOG_VOL("vfat_mount(%s, %d:%d): mount rc = %d", dev->major,k dev->minor, vol->mount_point, rc); #endif + free (devpath); return rc; } diff --git a/vold/volmgr_vfat.h b/vold/volmgr_vfat.h index 2bd9fed..d9cf04d 100644 --- a/vold/volmgr_vfat.h +++ b/vold/volmgr_vfat.h @@ -25,5 +25,5 @@ int vfat_identify(blkdev_t *blkdev); int vfat_check(blkdev_t *blkdev); -int vfat_mount(blkdev_t *blkdev, volume_t *vol); +int vfat_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode); #endif |