diff options
94 files changed, 3169 insertions, 5872 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk new file mode 100644 index 00000000..b84e1b65 --- /dev/null +++ b/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ @@ -895,9 +895,10 @@ int adb_main(int is_daemon) ** AID_GRAPHICS to access the frame buffer ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) ** AID_SDCARD_RW to allow writing to the SD card + ** AID_MOUNT to allow unmounting the SD card before rebooting */ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, - AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW }; + AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW, AID_MOUNT }; setgroups(sizeof(groups)/sizeof(groups[0]), groups); /* then switch user and group to "shell" */ @@ -33,7 +33,7 @@ #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information -#define ADB_SERVER_VERSION 25 // Increment this when we want to force users to start a new adb server +#define ADB_SERVER_VERSION 26 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; diff --git a/adb/commandline.c b/adb/commandline.c index 57567524..857cee3b 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -105,8 +105,8 @@ void help() " environment variable is used, which must\n" " be an absolute path.\n" " devices - list all connected devices\n" - " connect <host>:<port> - connect to a device via TCP/IP" - " disconnect <host>:<port> - disconnect from a TCP/IP device" + " connect <host>:<port> - connect to a device via TCP/IP\n" + " disconnect <host>:<port> - disconnect from a TCP/IP device\n" "\n" "device commands:\n" " adb push <local> <remote> - copy file/dir to device\n" @@ -126,9 +126,10 @@ void help() " dev:<character device name>\n" " jdwp:<process pid> (remote only)\n" " adb jdwp - list PIDs of processes hosting a JDWP transport\n" - " adb install [-l] [-r] <file> - push this package file to the device and install it\n" + " adb install [-l] [-r] [-s] <file> - push this package file to the device and install it\n" " ('-l' means forward-lock the app)\n" " ('-r' means reinstall the app, keeping its data)\n" + " ('-s' means install on SD card instead of internal storage)\n" " adb uninstall [-k] <package> - remove this app package from the device\n" " ('-k' means keep the data and cache directories)\n" " adb bugreport - return all information from the device\n" @@ -220,8 +221,8 @@ static void read_and_dump(int fd) if(errno == EINTR) continue; break; } - /* we want to output to stdout, so no adb_write here !! */ - unix_write(1, buf, len); + fwrite(buf, 1, len, stdout); + fflush(stdout); } } @@ -1255,17 +1256,25 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) { struct stat st; int err; - const char *const WHERE = "/data/local/tmp/%s"; + const char *const DATA_DEST = "/data/local/tmp/%s"; + const char *const SD_DEST = "/sdcard/tmp/%s"; + const char* where = DATA_DEST; char to[PATH_MAX]; char* filename = argv[argc - 1]; const char* p; + int i; + + for (i = 0; i < argc; i++) { + if (!strcmp(argv[i], "-s")) + where = SD_DEST; + } p = adb_dirstop(filename); if (p) { p++; - snprintf(to, sizeof to, WHERE, p); + snprintf(to, sizeof to, where, p); } else { - snprintf(to, sizeof to, WHERE, filename); + snprintf(to, sizeof to, where, filename); } if (p[0] == '\0') { } diff --git a/adb/services.c b/adb/services.c index b5df5542..487c7d37 100644 --- a/adb/services.c +++ b/adb/services.c @@ -176,9 +176,23 @@ void restart_usb_service(int fd, void *cookie) void reboot_service(int fd, void *arg) { char buf[100]; - int ret; + int pid, ret; sync(); + + /* Attempt to unmount the SD card first. + * No need to bother checking for errors. + */ + pid = fork(); + if (pid == 0) { + /* ask vdc to unmount it */ + execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount", + getenv("EXTERNAL_STORAGE"), "force", NULL); + } else if (pid > 0) { + /* wait until vdc succeeds or fails */ + waitpid(pid, &ret, 0); + } + ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (char *)arg); if (ret < 0) { diff --git a/adb/usb_linux.c b/adb/usb_linux.c index 66ee317e..bb868135 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -21,6 +21,7 @@ #include <sys/ioctl.h> #include <sys/types.h> +#include <sys/time.h> #include <dirent.h> #include <fcntl.h> #include <errno.h> @@ -287,6 +288,8 @@ static int usb_bulk_write(usb_handle *h, const void *data, int len) { struct usbdevfs_urb *urb = &h->urb_out; int res; + struct timeval tv; + struct timespec ts; memset(urb, 0, sizeof(*urb)); urb->type = USBDEVFS_URB_TYPE_BULK; @@ -313,8 +316,12 @@ static int usb_bulk_write(usb_handle *h, const void *data, int len) res = -1; h->urb_out_busy = 1; for(;;) { - adb_cond_wait(&h->notify, &h->lock); - if(h->dead) { + /* time out after five seconds */ + gettimeofday(&tv, NULL); + ts.tv_sec = tv.tv_sec + 5; + ts.tv_nsec = tv.tv_usec * 1000L; + res = pthread_cond_timedwait(&h->notify, &h->lock, &ts); + if(res < 0 || h->dead) { break; } if(h->urb_out_busy == 0) { diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index 73bf4184..7f3cb543 100644 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -59,6 +59,14 @@ #define VENDOR_ID_NVIDIA 0x0955 // Garmin-Asus's USB Vendor ID #define VENDOR_ID_GARMIN_ASUS 0x091E +// Sharp's USB Vendor ID +#define VENDOR_ID_SHARP 0x04dd +// ZTE's USB Vendor ID +#define VENDOR_ID_ZTE 0x19D2 +// Kyocera's USB Vendor ID +#define VENDOR_ID_KYOCERA 0x0482 +// Pantech's USB Vendor ID +#define VENDOR_ID_PANTECH 0x10A9 /** built-in vendor list */ @@ -75,6 +83,10 @@ int builtInVendorIds[] = { VENDOR_ID_DELL, VENDOR_ID_NVIDIA, VENDOR_ID_GARMIN_ASUS, + VENDOR_ID_SHARP, + VENDOR_ID_ZTE, + VENDOR_ID_KYOCERA, + VENDOR_ID_PANTECH, }; #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index b86f2a57..3c1cf024 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -9,6 +9,13 @@ LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c LOCAL_CFLAGS := -Wall LOCAL_MODULE := debuggerd +ifeq ($(ARCH_ARM_HAVE_VFP),true) +LOCAL_CFLAGS += -DWITH_VFP +endif # ARCH_ARM_HAVE_VFP +ifeq ($(ARCH_ARM_HAVE_VFP_D32),true) +LOCAL_CFLAGS += -DWITH_VFP_D32 +endif # ARCH_ARM_HAVE_VFP_D32 + LOCAL_STATIC_LIBRARIES := libcutils libc include $(BUILD_EXECUTABLE) @@ -23,14 +30,20 @@ LOCAL_MODULE_TAGS := eng LOCAL_SHARED_LIBRARIES := libcutils libc include $(BUILD_EXECUTABLE) -ifeq ($(TARGET_ARCH_VARIANT),armv7-a) +ifeq ($(ARCH_ARM_HAVE_VFP),true) include $(CLEAR_VARS) + +LOCAL_CFLAGS += -DWITH_VFP +ifeq ($(ARCH_ARM_HAVE_VFP_D32),true) +LOCAL_CFLAGS += -DWITH_VFP_D32 +endif # ARCH_ARM_HAVE_VFP_D32 + LOCAL_SRC_FILES := vfp-crasher.c vfp.S LOCAL_MODULE := vfp-crasher LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := eng LOCAL_SHARED_LIBRARIES := libcutils libc include $(BUILD_EXECUTABLE) -endif # TARGET_ARCH_VARIANT == armv7-a +endif # ARCH_ARM_HAVE_VFP == true endif # TARGET_ARCH == arm diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c index 7b987cf9..e850a2e6 100644 --- a/debuggerd/debuggerd.c +++ b/debuggerd/debuggerd.c @@ -42,6 +42,14 @@ #include "utility.h" +#ifdef WITH_VFP +#ifdef WITH_VFP_D32 +#define NUM_VFP_REGS 32 +#else +#define NUM_VFP_REGS 16 +#endif +#endif + /* Main entry point to get the backtrace from the crashing process */ extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map, unsigned int sp_list[], @@ -278,7 +286,7 @@ void dump_registers(int tfd, int pid, bool at_fault) " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr); -#if __ARM_NEON__ +#ifdef WITH_VFP struct user_vfp vfp_regs; int i; @@ -288,7 +296,7 @@ void dump_registers(int tfd, int pid, bool at_fault) return; } - for (i = 0; i < 32; i += 2) { + for (i = 0; i < NUM_VFP_REGS; i += 2) { _LOG(tfd, only_in_tombstone, " d%-2d %016llx d%-2d %016llx\n", i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]); diff --git a/debuggerd/vfp.S b/debuggerd/vfp.S index 21924152..9744f6f7 100644 --- a/debuggerd/vfp.S +++ b/debuggerd/vfp.S @@ -19,6 +19,7 @@ crash: fconstd d13, #13 fconstd d14, #14 fconstd d15, #15 +#ifdef WITH_VFP_D32 fconstd d16, #16 fconstd d17, #17 fconstd d18, #18 @@ -35,6 +36,7 @@ crash: fconstd d29, #29 fconstd d30, #30 fconstd d31, #31 +#endif mov r0, #0 str r0, [r0] bx lr diff --git a/fastboot/engine.c b/fastboot/engine.c index 4c7e197f..6d62c6e2 100644 --- a/fastboot/engine.c +++ b/fastboot/engine.c @@ -30,9 +30,17 @@ #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <sys/time.h> #include "fastboot.h" +double now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; +} + char *mkmsg(const char *fmt, ...) { char buf[256]; @@ -66,6 +74,8 @@ struct Action const char *msg; int (*func)(Action *a, int status, char *resp); + + double start; }; static Action *action_list = 0; @@ -76,7 +86,9 @@ static int cb_default(Action *a, int status, char *resp) if (status) { fprintf(stderr,"FAILED (%s)\n", resp); } else { - fprintf(stderr,"OKAY\n"); + double split = now(); + fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start)); + a->start = split; } return status; } @@ -101,6 +113,9 @@ static Action *queue_action(unsigned op, const char *fmt, ...) action_last = a; a->op = op; a->func = cb_default; + + a->start = -1; + return a; } @@ -166,7 +181,9 @@ static int cb_check(Action *a, int status, char *resp, int invert) if (invert) yes = !yes; if (yes) { - fprintf(stderr,"OKAY\n"); + double split = now(); + fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start)); + a->start = split; return 0; } @@ -263,9 +280,12 @@ void fb_execute_queue(usb_handle *usb) a = action_list; resp[FB_RESPONSE_SZ] = 0; + double start = -1; for (a = action_list; a; a = a->next) { + a->start = now(); + if (start < 0) start = a->start; if (a->msg) { - fprintf(stderr,"%s... ",a->msg); + fprintf(stderr,"%30s... ",a->msg); } if (a->op == OP_DOWNLOAD) { status = fb_download_data(usb, a->data, a->size); @@ -285,5 +305,7 @@ void fb_execute_queue(usb_handle *usb) die("bogus action"); } } + + fprintf(stderr,"finished. total time: %.3fs\n", (now() - start)); } diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index aedfce16..bed30b2a 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -231,11 +231,12 @@ void usage(void) " -c <cmdline> override kernel commandline\n" " -i <vendor id> specify a custom USB vendor id\n" " -b <base_addr> specify a custom kernel base address\n" + " -n <page size> specify the nand page size. default: 2048\n" ); exit(1); } -void *load_bootable_image(const char *kernel, const char *ramdisk, +void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk, unsigned *sz, const char *cmdline) { void *kdata = 0, *rdata = 0; @@ -276,7 +277,7 @@ void *load_bootable_image(const char *kernel, const char *ramdisk, } fprintf(stderr,"creating boot image...\n"); - bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, 2048, base_addr, &bsize); + bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize); if(bdata == 0) { fprintf(stderr,"failed to create boot.img\n"); return 0; @@ -548,6 +549,7 @@ int main(int argc, char **argv) int wants_reboot_bootloader = 0; void *data; unsigned sz; + unsigned page_size = 2048; skip(1); if (argc == 0) { @@ -570,6 +572,11 @@ int main(int argc, char **argv) require(2); base_addr = strtoul(argv[1], 0, 16); skip(2); + } else if(!strcmp(*argv, "-n")) { + require(2); + page_size = (unsigned)strtoul(argv[1], NULL, 0); + if (!page_size) die("invalid page size"); + skip(2); } else if(!strcmp(*argv, "-s")) { require(2); serial = argv[1]; @@ -629,7 +636,7 @@ int main(int argc, char **argv) rname = argv[0]; skip(1); } - data = load_bootable_image(kname, rname, &sz, cmdline); + data = load_bootable_image(page_size, kname, rname, &sz, cmdline); if (data == 0) return 1; fb_queue_download("boot.img", data, sz); fb_queue_command("boot", "booting"); @@ -659,7 +666,7 @@ int main(int argc, char **argv) } else { skip(3); } - data = load_bootable_image(kname, rname, &sz, cmdline); + data = load_bootable_image(page_size, kname, rname, &sz, cmdline); if (data == 0) die("cannot load bootable image"); fb_queue_flash(pname, data, sz); } else if(!strcmp(*argv, "flashall")) { diff --git a/include/android/bitmap.h b/include/android/bitmap.h deleted file mode 100644 index 5078277b..00000000 --- a/include/android/bitmap.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BITMAP_H -#define ANDROID_BITMAP_H - -#include <stdint.h> -#include <jni.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define ANDROID_BITMAP_RESUT_SUCCESS 0 -#define ANDROID_BITMAP_RESULT_BAD_PARAMETER -1 -#define ANDROID_BITMAP_RESULT_JNI_EXCEPTION -2 -#define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3 - -enum AndroidBitmapFormat { - ANDROID_BITMAP_FORMAT_NONE = 0, - ANDROID_BITMAP_FORMAT_RGBA_8888 = 1, - ANDROID_BITMAP_FORMAT_RGB_565 = 4, - ANDROID_BITMAP_FORMAT_RGBA_4444 = 7, - ANDROID_BITMAP_FORMAT_A_8 = 8, -}; - -typedef struct { - uint32_t width; - uint32_t height; - uint32_t stride; - int32_t format; - uint32_t flags; // 0 for now -} AndroidBitmapInfo; - -/** - * Given a java bitmap object, fill out the AndroidBitmap struct for it. - * If the call fails, the info parameter will be ignored - */ -int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, - AndroidBitmapInfo* info); - -/** - * Given a java bitmap object, attempt to lock the pixel address. - * Locking will ensure that the memory for the pixels will not move - * until the unlockPixels call, and ensure that, if the pixels had been - * previously purged, they will have been restored. - * - * If this call succeeds, it must be balanced by a call to - * AndroidBitmap_unlockPixels, after which time the address of the pixels should - * no longer be used. - * - * If this succeeds, *addrPtr will be set to the pixel address. If the call - * fails, addrPtr will be ignored. - */ -int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr); - -/** - * Call this to balanace a successful call to AndroidBitmap_lockPixels - */ -int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/vold/volmgr_vfat.h b/include/cutils/iosched_policy.h index d9cf04d9..07c5d1fc 100644 --- a/vold/volmgr_vfat.h +++ b/include/cutils/iosched_policy.h @@ -1,6 +1,5 @@ - /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +14,25 @@ * limitations under the License. */ -#ifndef _VOLMGR_VFAT_H -#define _VOLMGR_VFAT_H +#ifndef __CUTILS_IOSCHED_POLICY_H +#define __CUTILS_IOSCHED_POLICY_H -#include "volmgr.h" -#include "blkdev.h" +#ifdef __cplusplus +extern "C" { +#endif +typedef enum { + IoSchedClass_NONE, + IoSchedClass_RT, + IoSchedClass_BE, + IoSchedClass_IDLE, +} IoSchedClass; +extern int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio); +extern int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio); -int vfat_identify(blkdev_t *blkdev); -int vfat_check(blkdev_t *blkdev); -int vfat_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode); +#ifdef __cplusplus +} #endif + +#endif /* __CUTILS_IOSCHED_POLICY_H */ diff --git a/include/cutils/log.h b/include/cutils/log.h index ec3cac87..dd47c358 100644 --- a/include/cutils/log.h +++ b/include/cutils/log.h @@ -196,6 +196,91 @@ extern "C" { #define IF_LOGE() IF_LOG(LOG_ERROR, LOG_TAG) #endif + +// --------------------------------------------------------------------- + +/* + * Simplified macro to send a verbose system log message using the current LOG_TAG. + */ +#ifndef SLOGV +#if LOG_NDEBUG +#define SLOGV(...) ((void)0) +#else +#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#endif +#endif + +#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) + +#ifndef SLOGV_IF +#if LOG_NDEBUG +#define SLOGV_IF(cond, ...) ((void)0) +#else +#define SLOGV_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif +#endif + +/* + * Simplified macro to send a debug system log message using the current LOG_TAG. + */ +#ifndef SLOGD +#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGD_IF +#define SLOGD_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send an info system log message using the current LOG_TAG. + */ +#ifndef SLOGI +#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGI_IF +#define SLOGI_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send a warning system log message using the current LOG_TAG. + */ +#ifndef SLOGW +#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGW_IF +#define SLOGW_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + +/* + * Simplified macro to send an error system log message using the current LOG_TAG. + */ +#ifndef SLOGE +#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef SLOGE_IF +#define SLOGE_IF(cond, ...) \ + ( (CONDITION(cond)) \ + ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ + : (void)0 ) +#endif + + + // --------------------------------------------------------------------- /* @@ -338,6 +423,21 @@ typedef enum { #define android_logToFile(tag, file) (0) #define android_logToFd(tag, fd) (0) +typedef enum { + LOG_ID_MAIN = 0, + LOG_ID_RADIO = 1, + LOG_ID_EVENTS = 2, + LOG_ID_SYSTEM = 3, + + LOG_ID_MAX +} log_id_t; + +/* + * Send a simple string to the log. + */ +int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); +int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...); + #ifdef __cplusplus } diff --git a/include/cutils/logger.h b/include/cutils/logger.h index 3a08019a..b60f7ad5 100644 --- a/include/cutils/logger.h +++ b/include/cutils/logger.h @@ -25,6 +25,7 @@ struct logger_entry { #define LOGGER_LOG_MAIN "log/main" #define LOGGER_LOG_RADIO "log/radio" #define LOGGER_LOG_EVENTS "log/events" +#define LOGGER_LOG_SYSTEM "log/system" #define LOGGER_ENTRY_MAX_LEN (4*1024) #define LOGGER_ENTRY_MAX_PAYLOAD \ diff --git a/include/cutils/logprint.h b/include/cutils/logprint.h index d6ec480c..769c8a73 100644 --- a/include/cutils/logprint.h +++ b/include/cutils/logprint.h @@ -142,7 +142,7 @@ char *android_log_formatLogLine ( * Assumes single threaded execution * */ -int android_log_filterAndPrintLogLine( +int android_log_printLogLine( AndroidLogFormat *p_format, int fd, const AndroidLogEntry *entry); diff --git a/include/diskconfig/diskconfig.h b/include/diskconfig/diskconfig.h new file mode 100644 index 00000000..d4f468cd --- /dev/null +++ b/include/diskconfig/diskconfig.h @@ -0,0 +1,129 @@ +/* system/core/include/diskconfig/diskconfig.h + * + * Copyright 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 __LIBS_DISKCONFIG_H +#define __LIBS_DISKCONFIG_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_NAME_LEN 512 +#define MAX_NUM_PARTS 16 + +/* known partition schemes */ +#define PART_SCHEME_MBR 0x1 +#define PART_SCHEME_GPT 0x2 + +/* PC Bios partition status */ +#define PC_PART_ACTIVE 0x80 +#define PC_PART_NORMAL 0x0 + +/* Known (rather, used by us) partition types */ +#define PC_PART_TYPE_LINUX 0x83 +#define PC_PART_TYPE_EXTENDED 0x05 +#define PC_PART_TYPE_FAT32 0x0c + +#define PC_NUM_BOOT_RECORD_PARTS 4 + +#define PC_EBR_LOGICAL_PART 0 +#define PC_EBR_NEXT_PTR_PART 1 + +#define PC_BIOS_BOOT_SIG 0xAA55 + +#define PC_MBR_DISK_OFFSET 0 +#define PC_MBR_SIZE 512 + +#define PART_ACTIVE_FLAG 0x1 + +struct chs { + uint8_t head; + uint8_t sector; + uint8_t cylinder; +} __attribute__((__packed__)); + +/* 16 byte pc partition descriptor that sits in MBR and EPBR. + * Note: multi-byte entities have little-endian layout on disk */ +struct pc_partition { + uint8_t status; /* byte 0 */ + struct chs start; /* bytes 1-3 */ + uint8_t type; /* byte 4 */ + struct chs end; /* bytes 5-7 */ + uint32_t start_lba; /* bytes 8-11 */ + uint32_t len_lba; /* bytes 12-15 */ +} __attribute__((__packed__)); + +struct pc_boot_record { + uint8_t code[440]; /* bytes 0-439 */ + uint32_t disk_sig; /* bytes 440-443 */ + uint16_t pad; /* bytes 444-445 */ + struct pc_partition ptable[PC_NUM_BOOT_RECORD_PARTS]; /* bytes 446-509 */ + uint16_t mbr_sig; /* bytes 510-511 */ +} __attribute__((__packed__)); + +struct part_info { + char *name; + uint8_t flags; + uint8_t type; + uint32_t len_kb; /* in 1K-bytes */ + uint32_t start_lba; /* the LBA where this partition begins */ +}; + +struct disk_info { + char *device; + uint8_t scheme; + int sect_size; /* expected sector size in bytes. MUST BE POWER OF 2 */ + uint32_t skip_lba; /* in sectors (1 unit of LBA) */ + uint32_t num_lba; /* the size of the disk in LBA units */ + struct part_info *part_lst; + int num_parts; +}; + +struct write_list { + struct write_list *next; + loff_t offset; + uint32_t len; + uint8_t data[0]; +}; + + +struct write_list *alloc_wl(uint32_t data_len); +void free_wl(struct write_list *item); +struct write_list *wlist_add(struct write_list **lst, struct write_list *item); +void wlist_free(struct write_list *lst); +int wlist_commit(int fd, struct write_list *lst, int test); + +struct disk_info *load_diskconfig(const char *fn, char *path_override); +int dump_disk_config(struct disk_info *dinfo); +int apply_disk_config(struct disk_info *dinfo, int test); +char *find_part_device(struct disk_info *dinfo, const char *name); +int process_disk_config(struct disk_info *dinfo); +struct part_info *find_part(struct disk_info *dinfo, const char *name); + +int write_raw_image(const char *dst, const char *src, loff_t offset, int test); + +/* For MBR partition schemes */ +struct write_list *config_mbr(struct disk_info *dinfo); +char *find_mbr_part(struct disk_info *dinfo, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBS_DISKCONFIG_H */ diff --git a/include/pixelflinger/format.h b/include/pixelflinger/format.h index 6b2050c4..82eeca4d 100644 --- a/include/pixelflinger/format.h +++ b/include/pixelflinger/format.h @@ -39,19 +39,25 @@ enum GGLPixelFormat { GGL_PIXEL_FORMAT_LA_88 = 0xA, // 16-bit LA GGL_PIXEL_FORMAT_RGB_332 = 0xB, // 8-bit RGB (non paletted) - // 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 = 0x12, - GGL_PIXEL_FORMAT_YCbCr_420_P = 0x13, - GGL_PIXEL_FORMAT_YCbCr_422_I = 0x14, - GGL_PIXEL_FORMAT_YCbCr_420_I = 0x15, + // reserved range. don't use. + GGL_PIXEL_FORMAT_RESERVED_10 = 0x10, + GGL_PIXEL_FORMAT_RESERVED_11 = 0x11, + GGL_PIXEL_FORMAT_RESERVED_12 = 0x12, + GGL_PIXEL_FORMAT_RESERVED_13 = 0x13, + GGL_PIXEL_FORMAT_RESERVED_14 = 0x14, + GGL_PIXEL_FORMAT_RESERVED_15 = 0x15, + GGL_PIXEL_FORMAT_RESERVED_16 = 0x16, + GGL_PIXEL_FORMAT_RESERVED_17 = 0x17, // reserved/special formats GGL_PIXEL_FORMAT_Z_16 = 0x18, GGL_PIXEL_FORMAT_S_8 = 0x19, GGL_PIXEL_FORMAT_SZ_24 = 0x1A, GGL_PIXEL_FORMAT_SZ_8 = 0x1B, + + // reserved range. don't use. + GGL_PIXEL_FORMAT_RESERVED_20 = 0x20, + GGL_PIXEL_FORMAT_RESERVED_21 = 0x21, }; enum GGLFormatComponents { @@ -62,10 +68,6 @@ enum GGLFormatComponents { GGL_RGBA = 0x1908, GGL_LUMINANCE = 0x1909, GGL_LUMINANCE_ALPHA = 0x190A, - 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/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 24b7c819..474cfacb 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -156,9 +156,11 @@ static struct fs_path_config android_files[] = { { 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" }, { 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" }, { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" }, - { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/main.conf" }, - { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" }, - { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" }, + { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/main.conf" }, + { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/input.conf" }, + { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/audio.conf" }, + { 00444, AID_NET_BT, AID_NET_BT, "system/etc/bluetooth/blacklist.conf" }, + { 00640, AID_SYSTEM, AID_SYSTEM, "system/etc/bluetooth/auto_pairing.conf" }, { 00444, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" }, { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" }, { 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" }, @@ -167,14 +169,18 @@ static struct fs_path_config android_files[] = { /* the following two files are INTENTIONALLY set-gid and not set-uid. * Do not change. */ { 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" }, - { 02755, AID_ROOT, AID_INET, "system/bin/netcfg" }, - /* the following four files are INTENTIONALLY set-uid, but they + { 02750, AID_ROOT, AID_INET, "system/bin/netcfg" }, + /* the following five files are INTENTIONALLY set-uid, but they * are NOT included on user builds. */ { 06755, AID_ROOT, AID_ROOT, "system/xbin/su" }, { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" }, { 06755, AID_ROOT, AID_ROOT, "system/xbin/procrank" }, { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" }, { 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" }, + { 04770, AID_ROOT, AID_RADIO, "system/bin/pppd-ril" }, + /* the following file is INTENTIONALLY set-uid, and IS included + * in user builds. */ + { 06750, AID_ROOT, AID_SHELL, "system/bin/run-as" }, { 00755, AID_ROOT, AID_SHELL, "system/bin/*" }, { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" }, { 00750, AID_ROOT, AID_SHELL, "sbin/*" }, diff --git a/include/private/pixelflinger/ggl_context.h b/include/private/pixelflinger/ggl_context.h index 8a36fa9e..2d7fdcf5 100644 --- a/include/private/pixelflinger/ggl_context.h +++ b/include/private/pixelflinger/ggl_context.h @@ -285,8 +285,7 @@ struct clear_state_t { }; struct fog_state_t { - uint8_t color[3]; - uint8_t reserved; + uint8_t color[4]; }; struct logic_op_state_t { diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h index 4e3d3964..142f50c5 100644 --- a/include/sysutils/FrameworkListener.h +++ b/include/sysutils/FrameworkListener.h @@ -23,7 +23,7 @@ class SocketClient; class FrameworkListener : public SocketListener { public: - static const int CMD_ARGS_MAX = 8; + static const int CMD_ARGS_MAX = 16; private: FrameworkCommandCollection *mCommands; diff --git a/init/init.c b/init/init.c index 16a35303..4d98cc2f 100755 --- a/init/init.c +++ b/init/init.c @@ -35,6 +35,7 @@ #include <sys/reboot.h> #include <cutils/sockets.h> +#include <cutils/iosched_policy.h> #include <termios.h> #include <linux/kd.h> #include <linux/keychord.h> @@ -224,6 +225,13 @@ void service_start(struct service *svc, const char *dynamic_args) } } + if (svc->ioprio_class != IoSchedClass_NONE) { + if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) { + ERROR("Failed to set pid %d ioprio = %d,%d: %s\n", + getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno)); + } + } + if (needs_console) { setsid(); open_console(); diff --git a/init/init.h b/init/init.h index 60c30555..f92a4d7a 100644 --- a/init/init.h +++ b/init/init.h @@ -114,7 +114,7 @@ struct svcenvinfo { #define SVC_CONSOLE 0x10 /* requires console */ #define SVC_CRITICAL 0x20 /* will reboot into recovery if keeps crashing */ -#define NR_SVC_SUPP_GIDS 6 /* six supplementary groups */ +#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ #define SVC_MAXARGS 64 @@ -146,6 +146,9 @@ struct service { int nkeycodes; int keychord_id; + int ioprio_class; + int ioprio_pri; + int nargs; /* "MUST BE AT THE END OF THE STRUCT" */ char *args[1]; diff --git a/init/keywords.h b/init/keywords.h index 308118ef..254c7855 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -75,6 +75,7 @@ enum { KEYWORD(chmod, COMMAND, 2, do_chmod) KEYWORD(loglevel, COMMAND, 1, do_loglevel) KEYWORD(device, COMMAND, 4, do_device) + KEYWORD(ioprio, OPTION, 0, 0) #ifdef __MAKE_KEYWORD_ENUM__ KEYWORD_COUNT, }; diff --git a/init/parser.c b/init/parser.c index 54622cce..7da0d194 100644 --- a/init/parser.c +++ b/init/parser.c @@ -10,6 +10,8 @@ #include "init.h" #include "property_service.h" +#include <cutils/iosched_policy.h> + #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> @@ -155,6 +157,7 @@ int lookup_keyword(const char *s) if (!strcmp(s, "ostname")) return K_hostname; break; case 'i': + if (!strcmp(s, "oprio")) return K_ioprio; if (!strcmp(s, "fup")) return K_ifup; if (!strcmp(s, "nsmod")) return K_insmod; if (!strcmp(s, "mport")) return K_import; @@ -619,6 +622,8 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args return; } + svc->ioprio_class = IoSchedClass_NONE; + kw = lookup_keyword(args[0]); switch (kw) { case K_capability: @@ -636,6 +641,28 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args case K_disabled: svc->flags |= SVC_DISABLED; break; + case K_ioprio: + if (nargs != 3) { + parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n"); + } else { + svc->ioprio_pri = strtoul(args[2], 0, 8); + + if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) { + parse_error(state, "priority value must be range 0 - 7\n"); + break; + } + + if (!strcmp(args[1], "rt")) { + svc->ioprio_class = IoSchedClass_RT; + } else if (!strcmp(args[1], "be")) { + svc->ioprio_class = IoSchedClass_BE; + } else if (!strcmp(args[1], "idle")) { + svc->ioprio_class = IoSchedClass_IDLE; + } else { + parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n"); + } + } + break; case K_group: if (nargs < 2) { parse_error(state, "group option requires a group id\n"); diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 93933e2c..4c45cc92 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -38,7 +38,8 @@ commonSources := \ process_name.c \ properties.c \ threads.c \ - sched_policy.c + sched_policy.c \ + iosched_policy.c commonHostSources := \ ashmem-host.c diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c new file mode 100644 index 00000000..f350f58b --- /dev/null +++ b/libcutils/iosched_policy.c @@ -0,0 +1,67 @@ + +/* libs/cutils/iosched_policy.c +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#ifdef HAVE_SCHED_H + +#include <cutils/iosched_policy.h> + +extern int ioprio_set(int which, int who, int ioprio); + +enum { + WHO_PROCESS = 1, + WHO_PGRP, + WHO_USER, +}; + +#define CLASS_SHIFT 13 +#define IOPRIO_NORM 4 + +int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio) { +#ifdef HAVE_ANDROID_OS + if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) { + return -1; + } +#endif + return 0; +} + +int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio) { +#ifdef HAVE_ANDROID_OS + int rc; + + if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) { + return -1; + } + + *clazz = (rc >> CLASS_SHIFT); + *ioprio = (rc & 0xff); +#else + *clazz = IoSchedClass_NONE; + *ioprio = 0; +#endif + return 0; +} + +#endif /* HAVE_SCHED_H */ diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c index 8134aa13..3a18b0b6 100644 --- a/libcutils/sched_policy.c +++ b/libcutils/sched_policy.c @@ -53,7 +53,7 @@ static int add_tid_to_cgroup(int tid, const char *grp_name) sprintf(path, "/dev/cpuctl/%s/tasks", grp_name); if ((fd = open(path, O_WRONLY)) < 0) { - LOGE("add_tid_to_cgroup failed to open '%s' (%s)\n", path, + SLOGE("add_tid_to_cgroup failed to open '%s' (%s)\n", path, strerror(errno)); return -1; } @@ -67,7 +67,7 @@ static int add_tid_to_cgroup(int tid, const char *grp_name) */ if (errno == ESRCH) return 0; - LOGW("add_tid_to_cgroup failed to write '%s' (%s)\n", path, + SLOGW("add_tid_to_cgroup failed to write '%s' (%s)\n", path, strerror(errno)); return -1; } @@ -90,8 +90,9 @@ static inline void initialize() /* * Try to get the scheduler group. * - * The data from /proc/<pid>/cgroup looks like: + * The data from /proc/<pid>/cgroup looks (something) like: * 2:cpu:/bg_non_interactive + * 1:cpuacct:/ * * We return the part after the "/", which will be an empty string for * the default cgroup. If the string is longer than "bufLen", the string @@ -101,34 +102,57 @@ static int getSchedulerGroup(int tid, char* buf, size_t bufLen) { #ifdef HAVE_ANDROID_OS char pathBuf[32]; - char readBuf[256]; - ssize_t count; - int fd; + char lineBuf[256]; + FILE *fp; snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid); - if ((fd = open(pathBuf, O_RDONLY)) < 0) { + if (!(fp = fopen(pathBuf, "r"))) { return -1; } - count = read(fd, readBuf, sizeof(readBuf)); - if (count <= 0) { - close(fd); - errno = ENODATA; - return -1; - } - close(fd); + while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) { + char *next = lineBuf; + char *subsys; + char *grp; + size_t len; - readBuf[--count] = '\0'; /* remove the '\n', now count==strlen */ + /* Junk the first field */ + if (!strsep(&next, ":")) { + goto out_bad_data; + } - char* cp = strchr(readBuf, '/'); - if (cp == NULL) { - readBuf[sizeof(readBuf)-1] = '\0'; - errno = ENODATA; - return -1; + if (!(subsys = strsep(&next, ":"))) { + goto out_bad_data; + } + + if (strcmp(subsys, "cpu")) { + /* Not the subsys we're looking for */ + continue; + } + + if (!(grp = strsep(&next, ":"))) { + goto out_bad_data; + } + grp++; /* Drop the leading '/' */ + len = strlen(grp); + grp[len-1] = '\0'; /* Drop the trailing '\n' */ + + if (bufLen <= len) { + len = bufLen - 1; + } + strncpy(buf, grp, len); + buf[len] = '\0'; + fclose(fp); + return 0; } - memcpy(buf, cp+1, count); /* count-1 for cp+1, count+1 for NUL */ - return 0; + SLOGE("Failed to find cpu subsys"); + fclose(fp); + return -1; + out_bad_data: + SLOGE("Bad cgroup data {%s}", lineBuf); + fclose(fp); + return -1; #else errno = ENOSYS; return -1; @@ -195,11 +219,11 @@ int set_sched_policy(int tid, SchedPolicy policy) strncpy(thread_name, p, (q-p)); } if (policy == SP_BACKGROUND) { - LOGD("vvv tid %d (%s)", tid, thread_name); + SLOGD("vvv tid %d (%s)", tid, thread_name); } else if (policy == SP_FOREGROUND) { - LOGD("^^^ tid %d (%s)", tid, thread_name); + SLOGD("^^^ tid %d (%s)", tid, thread_name); } else { - LOGD("??? tid %d (%s)", tid, thread_name); + SLOGD("??? tid %d (%s)", tid, thread_name); } #endif diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk new file mode 100644 index 00000000..f2641031 --- /dev/null +++ b/libdiskconfig/Android.mk @@ -0,0 +1,20 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +ifneq ($(TARGET_SIMULATOR),true) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + diskconfig.c \ + diskutils.c \ + write_lst.c \ + config_mbr.c + +LOCAL_MODULE := libdiskconfig +LOCAL_PRELINK_MODULE := false +LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc + +include $(BUILD_SHARED_LIBRARY) + +endif # ! TARGET_SIMULATOR diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c new file mode 100644 index 00000000..825ba602 --- /dev/null +++ b/libdiskconfig/config_mbr.c @@ -0,0 +1,325 @@ +/* libs/diskconfig/diskconfig.c + * + * Copyright 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. + */ + +#define LOG_TAG "config_mbr" +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <cutils/log.h> + +#include <diskconfig/diskconfig.h> + + +/* start and len are in LBA units */ +static void +cfg_pentry(struct pc_partition *pentry, uint8_t status, uint8_t type, + uint32_t start, uint32_t len) +{ + if (len > 0) { + /* seems that somes BIOSens can get wedged on boot while verifying + * the mbr if these are 0 */ + memset(&pentry->start, 0xff, sizeof(struct chs)); + memset(&pentry->end, 0xff, sizeof(struct chs)); + } else { + /* zero out the c/h/s entries.. they are not used */ + memset(&pentry->start, 0, sizeof(struct chs)); + memset(&pentry->end, 0, sizeof(struct chs)); + } + + pentry->status = status; + pentry->type = type; + pentry->start_lba = start; + pentry->len_lba = len; + + LOGI("Configuring pentry. status=0x%x type=0x%x start_lba=%u len_lba=%u", + pentry->status, pentry->type, pentry->start_lba, pentry->len_lba); +} + + +static inline uint32_t +kb_to_lba(uint32_t len_kb, uint32_t sect_size) +{ + uint64_t lba; + + lba = (uint64_t)len_kb * 1024; + /* bump it up to the next LBA boundary just in case */ + lba = (lba + (uint64_t)sect_size - 1) & ~((uint64_t)sect_size - 1); + lba /= (uint64_t)sect_size; + if (lba >= 0xffffffffULL) + LOGE("Error converting kb -> lba. 32bit overflow, expect weirdness"); + return (uint32_t)(lba & 0xffffffffULL); +} + + +static struct write_list * +mk_pri_pentry(struct disk_info *dinfo, struct part_info *pinfo, int pnum, + uint32_t *lba) +{ + struct write_list *item; + struct pc_partition *pentry; + + if (pnum >= PC_NUM_BOOT_RECORD_PARTS) { + LOGE("Maximum number of primary partition exceeded."); + return NULL; + } + + if (!(item = alloc_wl(sizeof(struct pc_partition)))) { + LOGE("Unable to allocate memory for partition entry."); + return NULL; + } + + { + /* DO NOT DEREFERENCE */ + struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET; + /* grab the offset in mbr where to write this partition entry. */ + item->offset = (loff_t)((uint32_t)((uint8_t *)(&mbr->ptable[pnum]))); + } + + pentry = (struct pc_partition *) &item->data; + + /* need a standard primary partition entry */ + if (pinfo) { + /* need this to be 64 bit in case len_kb is large */ + uint64_t len_lba; + + if (pinfo->len_kb != (uint32_t)-1) { + /* bump it up to the next LBA boundary just in case */ + len_lba = ((uint64_t)pinfo->len_kb * 1024); + len_lba += ((uint64_t)dinfo->sect_size - 1); + len_lba &= ~((uint64_t)dinfo->sect_size - 1); + len_lba /= (uint64_t)dinfo->sect_size; + } else { + /* make it fill the rest of disk */ + len_lba = dinfo->num_lba - *lba; + } + + cfg_pentry(pentry, ((pinfo->flags & PART_ACTIVE_FLAG) ? + PC_PART_ACTIVE : PC_PART_NORMAL), + pinfo->type, *lba, (uint32_t)len_lba); + + pinfo->start_lba = *lba; + *lba += (uint32_t)len_lba; + } else { + /* this should be made an extended partition, and should take + * up the rest of the disk as a primary partition */ + cfg_pentry(pentry, PC_PART_NORMAL, PC_PART_TYPE_EXTENDED, + *lba, dinfo->num_lba - *lba); + + /* note that we do not update the *lba because we now have to + * create a chain of extended partition tables, and first one is at + * *lba */ + } + + return item; +} + + +/* This function configures an extended boot record at the beginning of an + * extended partition. This creates a logical partition and a pointer to + * the next EBR. + * + * ext_lba == The start of the toplevel extended partition (pointed to by the + * entry in the MBR). + */ +static struct write_list * +mk_ext_pentry(struct disk_info *dinfo, struct part_info *pinfo, uint32_t *lba, + uint32_t ext_lba, struct part_info *pnext) +{ + struct write_list *item; + struct pc_boot_record *ebr; + uint32_t len; /* in lba units */ + + if (!(item = alloc_wl(sizeof(struct pc_boot_record)))) { + LOGE("Unable to allocate memory for EBR."); + return NULL; + } + + /* we are going to write the ebr at the current LBA, and then bump the + * lba counter since that is where the logical data partition will start */ + item->offset = (*lba) * dinfo->sect_size; + (*lba)++; + + ebr = (struct pc_boot_record *) &item->data; + memset(ebr, 0, sizeof(struct pc_boot_record)); + ebr->mbr_sig = PC_BIOS_BOOT_SIG; + + if (pinfo->len_kb != (uint32_t)-1) + len = kb_to_lba(pinfo->len_kb, dinfo->sect_size); + else { + if (pnext) { + LOGE("Only the last partition can be specified to fill the disk " + "(name = '%s')", pinfo->name); + goto fail; + } + len = dinfo->num_lba - *lba; + /* update the pinfo structure to reflect the new size, for + * bookkeeping */ + pinfo->len_kb = + (uint32_t)(((uint64_t)len * (uint64_t)dinfo->sect_size) / + ((uint64_t)1024)); + } + + cfg_pentry(&ebr->ptable[PC_EBR_LOGICAL_PART], PC_PART_NORMAL, + pinfo->type, 1, len); + + pinfo->start_lba = *lba; + *lba += len; + + /* If this is not the last partition, we have to create a link to the + * next extended partition. + * + * Otherwise, there's nothing to do since the "pointer entry" is + * already zero-filled. + */ + if (pnext) { + /* The start lba for next partition is an offset from the beginning + * of the top-level extended partition */ + uint32_t next_start_lba = *lba - ext_lba; + uint32_t next_len_lba; + if (pnext->len_kb != (uint32_t)-1) + next_len_lba = 1 + kb_to_lba(pnext->len_kb, dinfo->sect_size); + else + next_len_lba = dinfo->num_lba - *lba; + cfg_pentry(&ebr->ptable[PC_EBR_NEXT_PTR_PART], PC_PART_NORMAL, + PC_PART_TYPE_EXTENDED, next_start_lba, next_len_lba); + } + + return item; + +fail: + free_wl(item); + return NULL; +} + + +struct write_list * +config_mbr(struct disk_info *dinfo) +{ + struct part_info *pinfo; + uint32_t cur_lba = dinfo->skip_lba; + uint32_t ext_lba = 0; + struct write_list *wr_list = NULL; + struct write_list *temp_wr = NULL; + int cnt = 0; + int extended = 0; + + if (!dinfo->part_lst) + return NULL; + + for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { + pinfo = &dinfo->part_lst[cnt]; + + /* Should we create an extedned partition? */ + if (cnt == (PC_NUM_BOOT_RECORD_PARTS - 1)) { + if (cnt + 1 < dinfo->num_parts) { + extended = 1; + ext_lba = cur_lba; + if ((temp_wr = mk_pri_pentry(dinfo, NULL, cnt, &cur_lba))) + wlist_add(&wr_list, temp_wr); + else { + LOGE("Cannot create primary extended partition."); + goto fail; + } + } + } + + /* if extended, need 1 lba for ebr */ + if ((cur_lba + extended) >= dinfo->num_lba) + goto nospace; + else if (pinfo->len_kb != (uint32_t)-1) { + uint32_t sz_lba = (pinfo->len_kb / dinfo->sect_size) * 1024; + if ((cur_lba + sz_lba + extended) > dinfo->num_lba) + goto nospace; + } + + if (!extended) + temp_wr = mk_pri_pentry(dinfo, pinfo, cnt, &cur_lba); + else { + struct part_info *pnext; + pnext = cnt + 1 < dinfo->num_parts ? &dinfo->part_lst[cnt+1] : NULL; + temp_wr = mk_ext_pentry(dinfo, pinfo, &cur_lba, ext_lba, pnext); + } + + if (temp_wr) + wlist_add(&wr_list, temp_wr); + else { + LOGE("Cannot create partition %d (%s).", cnt, pinfo->name); + goto fail; + } + } + + /* fill in the rest of the MBR with empty parts (if needed). */ + for (; cnt < PC_NUM_BOOT_RECORD_PARTS; ++cnt) { + struct part_info blank; + cur_lba = 0; + memset(&blank, 0, sizeof(struct part_info)); + if (!(temp_wr = mk_pri_pentry(dinfo, &blank, cnt, &cur_lba))) { + LOGE("Cannot create blank partition %d.", cnt); + goto fail; + } + wlist_add(&wr_list, temp_wr); + } + + return wr_list; + +nospace: + LOGE("Not enough space to add parttion '%s'.", pinfo->name); + +fail: + wlist_free(wr_list); + return NULL; +} + + +/* Returns the device path of the partition referred to by 'name' + * Must be freed by the caller. + */ +char * +find_mbr_part(struct disk_info *dinfo, const char *name) +{ + struct part_info *plist = dinfo->part_lst; + int num = 0; + char *dev_name = NULL; + int has_extended = (dinfo->num_parts > PC_NUM_BOOT_RECORD_PARTS); + + for(num = 1; num <= dinfo->num_parts; ++num) { + if (!strcmp(plist[num-1].name, name)) + break; + } + + if (num > dinfo->num_parts) + return NULL; + + if (has_extended && (num >= PC_NUM_BOOT_RECORD_PARTS)) + num++; + + if (!(dev_name = malloc(MAX_NAME_LEN))) { + LOGE("Cannot allocate memory."); + return NULL; + } + + num = snprintf(dev_name, MAX_NAME_LEN, "%s%d", dinfo->device, num); + if (num >= MAX_NAME_LEN) { + LOGE("Device name is too long?!"); + free(dev_name); + return NULL; + } + + return dev_name; +} diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c new file mode 100644 index 00000000..4dd8c526 --- /dev/null +++ b/libdiskconfig/diskconfig.c @@ -0,0 +1,536 @@ +/* libs/diskconfig/diskconfig.c + * + * Copyright 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. + */ + +#define LOG_TAG "diskconfig" + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <linux/fs.h> + +#include <cutils/config_utils.h> +#include <cutils/log.h> + +#include <diskconfig/diskconfig.h> + + +static int +parse_len(const char *str, uint64_t *plen) +{ + char tmp[64]; + int len_str; + uint32_t multiple = 1; + + strncpy(tmp, str, sizeof(tmp)); + tmp[sizeof(tmp)-1] = '\0'; + len_str = strlen(tmp); + if (!len_str) { + LOGE("Invalid disk length specified."); + return 1; + } + + switch(tmp[len_str - 1]) { + case 'M': case 'm': + /* megabyte */ + multiple <<= 10; + case 'K': case 'k': + /* kilobytes */ + multiple <<= 10; + tmp[len_str - 1] = '\0'; + break; + default: + break; + } + + *plen = strtoull(tmp, NULL, 0); + if (!*plen) { + LOGE("Invalid length specified: %s", str); + return 1; + } + + if (*plen == (uint64_t)-1) { + if (multiple > 1) { + LOGE("Size modifier illegal when len is -1"); + return 1; + } + } else { + /* convert len to kilobytes */ + if (multiple > 1024) + multiple >>= 10; + *plen *= multiple; + + if (*plen > 0xffffffffULL) { + LOGE("Length specified is too large!: %llu KB", *plen); + return 1; + } + } + + return 0; +} + + +static int +load_partitions(cnode *root, struct disk_info *dinfo) +{ + cnode *partnode; + + dinfo->num_parts = 0; + for (partnode = root->first_child; partnode; partnode = partnode->next) { + struct part_info *pinfo = &dinfo->part_lst[dinfo->num_parts]; + const char *tmp; + + /* bleh, i will leak memory here, but i DONT CARE since + * the only right thing to do when this function fails + * is to quit */ + pinfo->name = strdup(partnode->name); + + if(config_bool(partnode, "active", 0)) + pinfo->flags |= PART_ACTIVE_FLAG; + + if (!(tmp = config_str(partnode, "type", NULL))) { + LOGE("Partition type required: %s", pinfo->name); + return 1; + } + + /* possible values are: linux, fat32 */ + if (!strcmp(tmp, "linux")) { + pinfo->type = PC_PART_TYPE_LINUX; + } else if (!strcmp(tmp, "fat32")) { + pinfo->type = PC_PART_TYPE_FAT32; + } else { + LOGE("Unsupported partition type found: %s", tmp); + return 1; + } + + if ((tmp = config_str(partnode, "len", NULL)) != NULL) { + uint64_t len; + if (parse_len(tmp, &len)) + return 1; + pinfo->len_kb = (uint32_t) len; + } else + pinfo->len_kb = 0; + + ++dinfo->num_parts; + } + + return 0; +} + +struct disk_info * +load_diskconfig(const char *fn, char *path_override) +{ + struct disk_info *dinfo; + cnode *devroot; + cnode *partnode; + cnode *root = config_node("", ""); + const char *tmp; + + if (!(dinfo = malloc(sizeof(struct disk_info)))) { + LOGE("Could not malloc disk_info"); + return NULL; + } + memset(dinfo, 0, sizeof(struct disk_info)); + + if (!(dinfo->part_lst = malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) { + LOGE("Could not malloc part_lst"); + goto fail; + } + memset(dinfo->part_lst, 0, + (MAX_NUM_PARTS * sizeof(struct part_info))); + + config_load_file(root, fn); + if (root->first_child == NULL) { + LOGE("Could not read config file %s", fn); + goto fail; + } + + if (!(devroot = config_find(root, "device"))) { + LOGE("Could not find device section in config file '%s'", fn); + goto fail; + } + + + if (!(tmp = config_str(devroot, "path", path_override))) { + LOGE("device path is requried"); + goto fail; + } + dinfo->device = strdup(tmp); + + /* find the partition scheme */ + if (!(tmp = config_str(devroot, "scheme", NULL))) { + LOGE("partition scheme is required"); + goto fail; + } else if (!strcmp(tmp, "mbr")) { + dinfo->scheme = PART_SCHEME_MBR; + } else if (!strcmp(tmp, "gpt")) { + LOGE("'gpt' partition scheme not supported yet."); + goto fail; + } else { + LOGE("Unknown partition scheme specified: %s", tmp); + goto fail; + } + + /* grab the sector size (in bytes) */ + tmp = config_str(devroot, "sector_size", "512"); + dinfo->sect_size = strtol(tmp, NULL, 0); + if (!dinfo->sect_size) { + LOGE("Invalid sector size: %s", tmp); + goto fail; + } + + /* first lba where the partitions will start on disk */ + if (!(tmp = config_str(devroot, "start_lba", NULL))) { + LOGE("start_lba must be provided"); + goto fail; + } + + if (!(dinfo->skip_lba = strtol(tmp, NULL, 0))) { + LOGE("Invalid starting LBA (or zero): %s", tmp); + goto fail; + } + + /* Number of LBAs on disk */ + if (!(tmp = config_str(devroot, "num_lba", NULL))) { + LOGE("num_lba is required"); + goto fail; + } + dinfo->num_lba = strtoul(tmp, NULL, 0); + + if (!(partnode = config_find(devroot, "partitions"))) { + LOGE("Device must specify partition list"); + goto fail; + } + + if (load_partitions(partnode, dinfo)) + goto fail; + + return dinfo; + +fail: + if (dinfo->part_lst) + free(dinfo->part_lst); + if (dinfo->device) + free(dinfo->device); + free(dinfo); + return NULL; +} + +static int +sync_ptable(int fd) +{ + struct stat stat; + int rv; + + sync(); + + if (fstat(fd, &stat)) { + LOGE("Cannot stat, errno=%d.", errno); + return -1; + } + + if (S_ISBLK(stat.st_mode) && ((rv = ioctl(fd, BLKRRPART, NULL)) < 0)) { + LOGE("Could not re-read partition table. REBOOT!. (errno=%d)", errno); + return -1; + } + + return 0; +} + +/* This function verifies that the disk info provided is valid, and if so, + * returns an open file descriptor. + * + * This does not necessarily mean that it will later be successfully written + * though. If we use the pc-bios partitioning scheme, we must use extended + * partitions, which eat up some hd space. If the user manually provisioned + * every single partition, but did not account for the extra needed space, + * then we will later fail. + * + * TODO: Make validation more complete. + */ +static int +validate(struct disk_info *dinfo) +{ + int fd; + int sect_sz; + uint64_t disk_size; + uint64_t total_size; + int cnt; + struct stat stat; + + if (!dinfo) + return -1; + + if ((fd = open(dinfo->device, O_RDWR)) < 0) { + LOGE("Cannot open device '%s' (errno=%d)", dinfo->device, errno); + return -1; + } + + if (fstat(fd, &stat)) { + LOGE("Cannot stat file '%s', errno=%d.", dinfo->device, errno); + goto fail; + } + + + /* XXX: Some of the code below is kind of redundant and should probably + * be refactored a little, but it will do for now. */ + + /* Verify that we can operate on the device that was requested. + * We presently only support block devices and regular file images. */ + if (S_ISBLK(stat.st_mode)) { + /* get the sector size and make sure we agree */ + if (ioctl(fd, BLKSSZGET, §_sz) < 0) { + LOGE("Cannot get sector size (errno=%d)", errno); + goto fail; + } + + if (!sect_sz || sect_sz != dinfo->sect_size) { + LOGE("Device sector size is zero or sector sizes do not match!"); + goto fail; + } + + /* allow the user override the "disk size" if they provided num_lba */ + if (!dinfo->num_lba) { + if (ioctl(fd, BLKGETSIZE64, &disk_size) < 0) { + LOGE("Could not get block device size (errno=%d)", errno); + goto fail; + } + /* XXX: we assume that the disk has < 2^32 sectors :-) */ + dinfo->num_lba = (uint32_t)(disk_size / (uint64_t)dinfo->sect_size); + } else + disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size; + } else if (S_ISREG(stat.st_mode)) { + LOGI("Requesting operation on a regular file, not block device."); + if (!dinfo->sect_size) { + LOGE("Sector size for regular file images cannot be zero"); + goto fail; + } + if (dinfo->num_lba) + disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size; + else { + dinfo->num_lba = (uint32_t)(stat.st_size / dinfo->sect_size); + disk_size = (uint64_t)stat.st_size; + } + } else { + LOGE("Device does not refer to a regular file or a block device!"); + goto fail; + } + +#if 1 + LOGV("Device/file %s: size=%llu bytes, num_lba=%u, sect_size=%d", + dinfo->device, disk_size, dinfo->num_lba, dinfo->sect_size); +#endif + + /* since this is our offset into the disk, we start off with that as + * our size of needed partitions */ + total_size = dinfo->skip_lba * dinfo->sect_size; + + /* add up all the partition sizes and make sure it fits */ + for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { + struct part_info *part = &dinfo->part_lst[cnt]; + if (part->len_kb != (uint32_t)-1) { + total_size += part->len_kb * 1024; + } else if (part->len_kb == 0) { + LOGE("Zero-size partition '%s' is invalid.", part->name); + goto fail; + } else { + /* the partition requests the rest of the disk. */ + if (cnt + 1 != dinfo->num_parts) { + LOGE("Only the last partition in the list can request to fill " + "the rest of disk."); + goto fail; + } + } + + if ((part->type != PC_PART_TYPE_LINUX) && + (part->type != PC_PART_TYPE_FAT32)) { + LOGE("Unknown partition type (0x%x) encountered for partition " + "'%s'\n", part->type, part->name); + goto fail; + } + } + + /* only matters for disks, not files */ + if (S_ISBLK(stat.st_mode) && total_size > disk_size) { + LOGE("Total requested size of partitions (%llu) is greater than disk " + "size (%llu).", total_size, disk_size); + goto fail; + } + + return fd; + +fail: + close(fd); + return -1; +} + +static int +validate_and_config(struct disk_info *dinfo, int *fd, struct write_list **lst) +{ + *lst = NULL; + *fd = -1; + + if ((*fd = validate(dinfo)) < 0) + return 1; + + switch (dinfo->scheme) { + case PART_SCHEME_MBR: + *lst = config_mbr(dinfo); + return *lst == NULL; + case PART_SCHEME_GPT: + /* not supported yet */ + default: + LOGE("Uknown partition scheme."); + break; + } + + close(*fd); + *lst = NULL; + return 1; +} + +/* validate and process the disk layout configuration. + * This will cause an update to the partitions' start lba. + * + * Basically, this does the same thing as apply_disk_config in test mode, + * except that wlist_commit is not called to print out the data to be + * written. + */ +int +process_disk_config(struct disk_info *dinfo) +{ + struct write_list *lst; + int fd; + + if (validate_and_config(dinfo, &fd, &lst) != 0) + return 1; + + close(fd); + wlist_free(lst); + return 0; +} + + +int +apply_disk_config(struct disk_info *dinfo, int test) +{ + int fd; + struct write_list *wr_lst = NULL; + int rv; + + if (validate_and_config(dinfo, &fd, &wr_lst) != 0) { + LOGE("Configuration is invalid."); + goto fail; + } + + if ((rv = wlist_commit(fd, wr_lst, test)) >= 0) + rv = test ? 0 : sync_ptable(fd); + + close(fd); + wlist_free(wr_lst); + return rv; + +fail: + close(fd); + if (wr_lst) + wlist_free(wr_lst); + return 1; +} + +int +dump_disk_config(struct disk_info *dinfo) +{ + int cnt; + struct part_info *part; + + printf("Device: %s\n", dinfo->device); + printf("Scheme: "); + switch (dinfo->scheme) { + case PART_SCHEME_MBR: + printf("MBR"); + break; + case PART_SCHEME_GPT: + printf("GPT (unsupported)"); + break; + default: + printf("Unknown"); + break; + } + printf ("\n"); + + printf("Sector size: %d\n", dinfo->sect_size); + printf("Skip leading LBAs: %u\n", dinfo->skip_lba); + printf("Number of LBAs: %u\n", dinfo->num_lba); + printf("Partitions:\n"); + + for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { + part = &dinfo->part_lst[cnt]; + printf("\tname = %s\n", part->name); + printf("\t\tflags = %s\n", + part->flags & PART_ACTIVE_FLAG ? "Active" : "None"); + printf("\t\ttype = %s\n", + part->type == PC_PART_TYPE_LINUX ? "Linux" : "Unknown"); + if (part->len_kb == (uint32_t)-1) + printf("\t\tlen = rest of disk\n"); + else + printf("\t\tlen = %uKB\n", part->len_kb); + } + printf("Total number of partitions: %d\n", cnt); + printf("\n"); + + return 0; +} + +struct part_info * +find_part(struct disk_info *dinfo, const char *name) +{ + struct part_info *pinfo; + int cnt; + + for (cnt = 0; cnt < dinfo->num_parts; ++cnt) { + pinfo = &dinfo->part_lst[cnt]; + if (!strcmp(pinfo->name, name)) + return pinfo; + } + + return NULL; +} + +/* NOTE: If the returned ptr is non-NULL, it must be freed by the caller. */ +char * +find_part_device(struct disk_info *dinfo, const char *name) +{ + switch (dinfo->scheme) { + case PART_SCHEME_MBR: + return find_mbr_part(dinfo, name); + case PART_SCHEME_GPT: + LOGE("GPT is presently not supported"); + break; + default: + LOGE("Unknown partition table scheme"); + break; + } + + return NULL; +} + + diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c new file mode 100644 index 00000000..22767c00 --- /dev/null +++ b/libdiskconfig/diskutils.c @@ -0,0 +1,117 @@ +/* libs/diskconfig/diskutils.c + * + * Copyright 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. + */ + +#define LOG_TAG "diskutils" + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <cutils/log.h> + +#include <diskconfig/diskconfig.h> + +int +write_raw_image(const char *dst, const char *src, loff_t offset, int test) +{ + int dst_fd = -1; + int src_fd = -1; + uint8_t buffer[2048]; + int nr_bytes; + int tmp; + int done = 0; + uint64_t total = 0; + + LOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, offset); + if ((src_fd = open(src, O_RDONLY)) < 0) { + LOGE("Could not open %s for reading (errno=%d).", src, errno); + goto fail; + } + + if (!test) { + if ((dst_fd = open(dst, O_RDWR)) < 0) { + LOGE("Could not open '%s' for read/write (errno=%d).", dst, errno); + goto fail; + } + + if (lseek64(dst_fd, offset, SEEK_SET) != offset) { + LOGE("Could not seek to offset %lld in %s.", offset, dst); + goto fail; + } + } + + while (!done) { + if ((nr_bytes = read(src_fd, buffer, sizeof(buffer))) < 0) { + /* XXX: Should we not even bother with EINTR? */ + if (errno == EINTR) + continue; + LOGE("Error (%d) while reading from '%s'", errno, src); + goto fail; + } + + if (!nr_bytes) { + /* we're done. */ + done = 1; + break; + } + + total += nr_bytes; + + /* skip the write loop if we're testing */ + if (test) + nr_bytes = 0; + + while (nr_bytes > 0) { + if ((tmp = write(dst_fd, buffer, nr_bytes)) < 0) { + /* XXX: Should we not even bother with EINTR? */ + if (errno == EINTR) + continue; + LOGE("Error (%d) while writing to '%s'", errno, dst); + goto fail; + } + if (!tmp) + continue; + nr_bytes -= tmp; + } + } + + if (!done) { + LOGE("Exited read/write loop without setting flag! WTF?!"); + goto fail; + } + + if (dst_fd >= 0) + fsync(dst_fd); + + LOGI("Wrote %llu bytes to %s @ %lld", total, dst, offset); + + close(src_fd); + if (dst_fd >= 0) + close(dst_fd); + return 0; + +fail: + if (dst_fd >= 0) + close(dst_fd); + if (src_fd >= 0) + close(src_fd); + return 1; +} diff --git a/vold/switch.h b/libdiskconfig/dump_diskconfig.c index 6729f2df..fff19f5a 100644 --- a/vold/switch.h +++ b/libdiskconfig/dump_diskconfig.c @@ -1,12 +1,12 @@ - -/* - * Copyright (C) 2008 The Android Open Source Project +/* libs/diskconfig/dump_diskconfig.c + * + * Copyright 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 + * 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, @@ -15,11 +15,28 @@ * limitations under the License. */ -#ifndef _SWITCH_H -#define _SWITCH_H +#define LOG_TAG "dump_diskconfig" +#include <stdio.h> + +#include <cutils/log.h> + +#include "diskconfig.h" + +int +main(int argc, char *argv[]) +{ + struct disk_info *dinfo; + + if (argc < 2) { + LOGE("usage: %s <conf file>", argv[0]); + return 1; + } + + if (!(dinfo = load_diskconfig(argv[1], NULL))) + return 1; -#include "vold.h" + dump_disk_config(dinfo); -#define SYSFS_CLASS_SWITCH_PATH "/sys/class/switch" + return 0; +} -#endif diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c new file mode 100644 index 00000000..12b7cd77 --- /dev/null +++ b/libdiskconfig/write_lst.c @@ -0,0 +1,92 @@ +/* libs/diskconfig/write_lst.c + * + * Copyright 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. + */ + +#define LOG_TAG "write_lst" +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <cutils/log.h> + +#include <diskconfig/diskconfig.h> + +struct write_list * +alloc_wl(uint32_t data_len) +{ + struct write_list *item; + + if (!(item = malloc(sizeof(struct write_list) + data_len))) { + LOGE("Unable to allocate memory."); + return NULL; + } + + item->len = data_len; + return item; +} + +void +free_wl(struct write_list *item) +{ + if (item) + free(item); +} + +struct write_list * +wlist_add(struct write_list **lst, struct write_list *item) +{ + item->next = (*lst); + *lst = item; + return item; +} + +void +wlist_free(struct write_list *lst) +{ + struct write_list *temp_wr; + while (lst) { + temp_wr = lst->next; + free_wl(lst); + lst = temp_wr; + } +} + +int +wlist_commit(int fd, struct write_list *lst, int test) +{ + for(; lst; lst = lst->next) { + if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) { + LOGE("Cannot seek to the specified position (%lld).", lst->offset); + goto fail; + } + + if (!test) { + if (write(fd, lst->data, lst->len) != (int)lst->len) { + LOGE("Failed writing %u bytes at position %lld.", lst->len, + lst->offset); + goto fail; + } + } else + LOGI("Would write %d bytes @ offset %lld.", lst->len, lst->offset); + } + + return 0; + +fail: + return -1; +} diff --git a/libjnigraphics/Android.mk b/libjnigraphics/Android.mk deleted file mode 100644 index 9458f282..00000000 --- a/libjnigraphics/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -BASE_PATH := $(call my-dir) -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_PRELINK_MODULE := false - -# setup for skia optimizations -# -ifneq ($(ARCH_ARM_HAVE_VFP),true) - LOCAL_CFLAGS += -DSK_SOFTWARE_FLOAT -endif - -ifeq ($(ARCH_ARM_HAVE_NEON),true) - LOCAL_CFLAGS += -D__ARM_HAVE_NEON -endif - -# our source files -# -LOCAL_SRC_FILES:= \ - bitmap.cpp - -LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ - libskia - -LOCAL_C_INCLUDES += \ - external/skia/include/core \ - frameworks/base/core/jni/android/graphics \ - dalvik/libnativehelper/include/nativehelper - -LOCAL_MODULE:= libjnigraphics - -include $(BUILD_SHARED_LIBRARY) - diff --git a/libjnigraphics/bitmap.cpp b/libjnigraphics/bitmap.cpp deleted file mode 100644 index fd73430b..00000000 --- a/libjnigraphics/bitmap.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android/bitmap.h> -#include <GraphicsJNI.h> - -int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, - AndroidBitmapInfo* info) { - if (NULL == env || NULL == jbitmap) { - return ANDROID_BITMAP_RESULT_BAD_PARAMETER; - } - - SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap); - if (NULL == bm) { - return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; - } - - if (info) { - info->width = bm->width(); - info->height = bm->height(); - info->stride = bm->rowBytes(); - info->flags = 0; - - switch (bm->config()) { - case SkBitmap::kARGB_8888_Config: - info->format = ANDROID_BITMAP_FORMAT_RGBA_8888; - break; - case SkBitmap::kRGB_565_Config: - info->format = ANDROID_BITMAP_FORMAT_RGB_565; - break; - case SkBitmap::kARGB_4444_Config: - info->format = ANDROID_BITMAP_FORMAT_RGBA_4444; - break; - case SkBitmap::kA8_Config: - info->format = ANDROID_BITMAP_FORMAT_A_8; - break; - default: - info->format = ANDROID_BITMAP_FORMAT_NONE; - break; - } - } - return ANDROID_BITMAP_RESUT_SUCCESS; -} - -int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) { - if (NULL == env || NULL == jbitmap) { - return ANDROID_BITMAP_RESULT_BAD_PARAMETER; - } - - SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap); - if (NULL == bm) { - return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; - } - - bm->lockPixels(); - void* addr = bm->getPixels(); - if (NULL == addr) { - bm->unlockPixels(); - return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED; - } - - if (addrPtr) { - *addrPtr = addr; - } - return ANDROID_BITMAP_RESUT_SUCCESS; -} - -int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) { - if (NULL == env || NULL == jbitmap) { - return ANDROID_BITMAP_RESULT_BAD_PARAMETER; - } - - SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap); - if (NULL == bm) { - return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; - } - - bm->unlockPixels(); - return ANDROID_BITMAP_RESUT_SUCCESS; -} - diff --git a/liblog/logd_write.c b/liblog/logd_write.c index 241dbf0c..9923bba9 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -27,6 +27,7 @@ #include <cutils/logger.h> #include <cutils/logd.h> +#include <cutils/log.h> #define LOG_BUF_SIZE 1024 @@ -41,21 +42,13 @@ #define log_close(filedes) close(filedes) #endif -typedef enum { - LOG_ID_MAIN = 0, - LOG_ID_RADIO, - LOG_ID_EVENTS, - LOG_ID_MAX -} log_id_t; - static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); -static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = - __write_to_log_init; +static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; #ifdef HAVE_PTHREADS static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; #endif -static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1 }; +static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 }; /* * This is used by the C++ code to decide if it should write logs through @@ -110,6 +103,7 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); + log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); write_to_log = __write_to_log_kernel; @@ -123,6 +117,10 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) log_fds[LOG_ID_EVENTS] = -1; write_to_log = __write_to_log_null; } + + if (log_fds[LOG_ID_SYSTEM] < 0) { + log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; + } } #ifdef HAVE_PTHREADS @@ -161,6 +159,34 @@ int __android_log_write(int prio, const char *tag, const char *msg) return write_to_log(log_id, vec, 3); } +int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) +{ + struct iovec vec[3]; + + if (!tag) + tag = ""; + + /* XXX: This needs to go! */ + if (!strcmp(tag, "HTC_RIL") || + !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ + !strcmp(tag, "AT") || + !strcmp(tag, "GSM") || + !strcmp(tag, "STK") || + !strcmp(tag, "CDMA") || + !strcmp(tag, "PHONE") || + !strcmp(tag, "SMS")) + bufID = LOG_ID_RADIO; + + vec[0].iov_base = (unsigned char *) &prio; + vec[0].iov_len = 1; + vec[1].iov_base = (void *) tag; + vec[1].iov_len = strlen(tag) + 1; + vec[2].iov_base = (void *) msg; + vec[2].iov_len = strlen(msg) + 1; + + return write_to_log(bufID, vec, 3); +} + int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) { char buf[LOG_BUF_SIZE]; @@ -173,7 +199,7 @@ int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) int __android_log_print(int prio, const char *tag, const char *fmt, ...) { va_list ap; - char buf[LOG_BUF_SIZE]; + char buf[LOG_BUF_SIZE]; va_start(ap, fmt); vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); @@ -182,6 +208,18 @@ int __android_log_print(int prio, const char *tag, const char *fmt, ...) return __android_log_write(prio, tag, buf); } +int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) +{ + va_list ap; + char buf[LOG_BUF_SIZE]; + + va_start(ap, fmt); + vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); + va_end(ap); + + return __android_log_buf_write(bufID, prio, tag, buf); +} + void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) { diff --git a/liblog/logprint.c b/liblog/logprint.c index 080f9e36..4c5b3e57 100644 --- a/liblog/logprint.c +++ b/liblog/logprint.c @@ -753,6 +753,16 @@ char *android_log_formatLogLine ( suffixLen = 1; break; } + /* snprintf has a weird return value. It returns what would have been + * written given a large enough buffer. In the case that the prefix is + * longer then our buffer(128), it messes up the calculations below + * possibly causing heap corruption. To avoid this we double check and + * set the length at the maximum (size minus null byte) + */ + if(prefixLen >= sizeof(prefixBuf)) + prefixLen = sizeof(prefixBuf) - 1; + if(suffixLen >= sizeof(suffixBuf)) + suffixLen = sizeof(suffixBuf) - 1; /* the following code is tragically unreadable */ @@ -840,7 +850,7 @@ char *android_log_formatLogLine ( * Returns count bytes written */ -int android_log_filterAndPrintLogLine( +int android_log_printLogLine( AndroidLogFormat *p_format, int fd, const AndroidLogEntry *entry) @@ -850,11 +860,6 @@ int android_log_filterAndPrintLogLine( char *outBuffer = NULL; size_t totalLen; - if (0 == android_log_shouldPrintLine(p_format, entry->tag, - entry->priority)) { - return 0; - } - outBuffer = android_log_formatLogLine(p_format, defaultBuffer, sizeof(defaultBuffer), entry, &totalLen); diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp index 161e6d6e..6546e8c0 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_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 + { 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 { 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 @@ -53,6 +53,15 @@ static GGLFormat const gPixelFormatInfos[] = { 1, 8, {{ 8, 0, 0, 0, 0, 0, 0, 0 }}, GGL_STENCIL_INDEX }, { 4, 24, {{ 0, 0, 24, 0, 0, 0, 0, 0 }}, GGL_DEPTH_COMPONENT}, { 4, 8, {{ 32,24, 0, 0, 0, 0, 0, 0 }}, GGL_STENCIL_INDEX }, + + { 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 + + { 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 + }; }; // namespace android diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp index b54da0c6..84e584e4 100644 --- a/libpixelflinger/pixelflinger.cpp +++ b/libpixelflinger/pixelflinger.cpp @@ -281,6 +281,7 @@ static void ggl_fogColor3xv(void* con, const GGLclampx* color) const int32_t r = gglClampx(color[0]); const int32_t g = gglClampx(color[1]); const int32_t b = gglClampx(color[2]); + c->state.fog.color[GGLFormat::ALPHA]= 0xFF; // unused c->state.fog.color[GGLFormat::RED] = (r - (r>>8))>>8; c->state.fog.color[GGLFormat::GREEN]= (g - (g>>8))>>8; c->state.fog.color[GGLFormat::BLUE] = (b - (b>>8))>>8; diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp index 16869961..562dd676 100644 --- a/libsysutils/src/FrameworkClient.cpp +++ b/libsysutils/src/FrameworkClient.cpp @@ -21,7 +21,7 @@ int FrameworkClient::sendMsg(const char *msg) { pthread_mutex_lock(&mWriteMutex); if (write(mSocket, msg, strlen(msg) +1) < 0) { - LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); + SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); } pthread_mutex_unlock(&mWriteMutex); return 0; diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp index c52eac76..038d87ed 100644 --- a/libsysutils/src/FrameworkCommand.cpp +++ b/libsysutils/src/FrameworkCommand.cpp @@ -26,7 +26,7 @@ FrameworkCommand::FrameworkCommand(const char *cmd) { } int FrameworkCommand::runCommand(SocketClient *c, int argc, char **argv) { - LOGW("Command %s has no run handler!", getCommand()); + SLOGW("Command %s has no run handler!", getCommand()); errno = ENOSYS; return -1; } diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp index 4c747650..80f678d0 100644 --- a/libsysutils/src/FrameworkListener.cpp +++ b/libsysutils/src/FrameworkListener.cpp @@ -34,7 +34,7 @@ bool FrameworkListener::onDataAvailable(SocketClient *c) { int len; if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) { - LOGE("read() failed (%s)", strerror(errno)); + SLOGE("read() failed (%s)", strerror(errno)); return errno; } else if (!len) return false; @@ -114,7 +114,7 @@ void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { argv[argc++] = strdup(tmp); #if 0 for (k = 0; k < argc; k++) { - LOGD("arg[%d] = '%s'", k, argv[k]); + SLOGD("arg[%d] = '%s'", k, argv[k]); } #endif @@ -128,7 +128,7 @@ void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { if (!strcmp(argv[0], c->getCommand())) { if (c->runCommand(cli, argc, argv)) { - LOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); + SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } goto out; } diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 1550d831..c2ba6477 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -52,7 +52,7 @@ void NetlinkEvent::dump() { for (i = 0; i < NL_PARAMS_MAX; i++) { if (!mParams[i]) break; - LOGD("NL param '%s'\n", mParams[i]); + SLOGD("NL param '%s'\n", mParams[i]); } } @@ -102,6 +102,6 @@ const char *NetlinkEvent::findParam(const char *paramName) { return &mParams[i][strlen(paramName) + 1]; } - LOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); + SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); return NULL; } diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp index 5586dccf..e2a354e4 100644 --- a/libsysutils/src/NetlinkListener.cpp +++ b/libsysutils/src/NetlinkListener.cpp @@ -35,13 +35,13 @@ bool NetlinkListener::onDataAvailable(SocketClient *cli) int count; if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) { - LOGE("recv failed (%s)", strerror(errno)); + SLOGE("recv failed (%s)", strerror(errno)); return false; } NetlinkEvent *evt = new NetlinkEvent(); if (!evt->decode(mBuffer, count)) { - LOGE("Error decoding NetlinkEvent"); + SLOGE("Error decoding NetlinkEvent"); goto out; } diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp index 700ac91b..60b161aa 100644 --- a/libsysutils/src/ServiceManager.cpp +++ b/libsysutils/src/ServiceManager.cpp @@ -11,11 +11,11 @@ ServiceManager::ServiceManager() { int ServiceManager::start(const char *name) { if (isRunning(name)) { - LOGW("Service '%s' is already running", name); + SLOGW("Service '%s' is already running", name); return 0; } - LOGD("Starting service '%s'", name); + SLOGD("Starting service '%s'", name); property_set("ctl.start", name); int count = 200; @@ -25,21 +25,21 @@ int ServiceManager::start(const char *name) { break; } if (!count) { - LOGW("Timed out waiting for service '%s' to start", name); + SLOGW("Timed out waiting for service '%s' to start", name); errno = ETIMEDOUT; return -1; } - LOGD("Sucessfully started '%s'", name); + SLOGD("Sucessfully started '%s'", name); return 0; } int ServiceManager::stop(const char *name) { if (!isRunning(name)) { - LOGW("Service '%s' is already stopped", name); + SLOGW("Service '%s' is already stopped", name); return 0; } - LOGD("Stopping service '%s'", name); + SLOGD("Stopping service '%s'", name); property_set("ctl.stop", name); int count = 200; @@ -50,11 +50,11 @@ int ServiceManager::stop(const char *name) { } if (!count) { - LOGW("Timed out waiting for service '%s' to stop", name); + SLOGW("Timed out waiting for service '%s' to stop", name); errno = ETIMEDOUT; return -1; } - LOGD("Sucessfully stopped '%s'", name); + SLOGD("Sucessfully stopped '%s'", name); return 0; } diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp index 857ed4d1..e9ae23a9 100644 --- a/libsysutils/src/SocketClient.cpp +++ b/libsysutils/src/SocketClient.cpp @@ -41,11 +41,11 @@ int SocketClient::sendMsg(const char *msg) { pthread_mutex_lock(&mWriteMutex); while(brtw) { if ((rc = write(mSocket,p, brtw)) < 0) { - LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); + SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); pthread_mutex_unlock(&mWriteMutex); return -1; } else if (!rc) { - LOGW("0 length write :("); + SLOGW("0 length write :("); errno = EIO; pthread_mutex_unlock(&mWriteMutex); return -1; diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp index 72e128db..7af221f7 100644 --- a/libsysutils/src/SocketListener.cpp +++ b/libsysutils/src/SocketListener.cpp @@ -64,30 +64,30 @@ SocketListener::~SocketListener() { int SocketListener::startListener() { if (!mSocketName && mSock == -1) { - LOGE("Failed to start unbound listener"); + SLOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) { - LOGE("Obtaining file descriptor socket '%s' failed: %s", + SLOGE("Obtaining file descriptor socket '%s' failed: %s", mSocketName, strerror(errno)); return -1; } } if (mListen && listen(mSock, 4) < 0) { - LOGE("Unable to listen on socket (%s)", strerror(errno)); + SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen) mClients->push_back(new SocketClient(mSock)); if (pipe(mCtrlPipe)) { - LOGE("pipe failed (%s)", strerror(errno)); + SLOGE("pipe failed (%s)", strerror(errno)); return -1; } if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { - LOGE("pthread_create (%s)", strerror(errno)); + SLOGE("pthread_create (%s)", strerror(errno)); return -1; } @@ -98,13 +98,13 @@ int SocketListener::stopListener() { char c = 0; if (write(mCtrlPipe[1], &c, 1) != 1) { - LOGE("Error writing to control pipe (%s)", strerror(errno)); + SLOGE("Error writing to control pipe (%s)", strerror(errno)); return -1; } void *ret; if (pthread_join(mThread, &ret)) { - LOGE("Error joining to listener thread (%s)", strerror(errno)); + SLOGE("Error joining to listener thread (%s)", strerror(errno)); return -1; } close(mCtrlPipe[0]); @@ -161,7 +161,7 @@ void SocketListener::runListener() { pthread_mutex_unlock(&mClientsLock); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { - LOGE("select failed (%s)", strerror(errno)); + SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; } else if (!rc) @@ -175,7 +175,7 @@ void SocketListener::runListener() { int c; if ((c = accept(mSock, &addr, &alen)) < 0) { - LOGE("accept failed (%s)", strerror(errno)); + SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } @@ -212,7 +212,7 @@ void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { for (i = mClients->begin(); i != mClients->end(); ++i) { if ((*i)->sendMsg(code, msg, addErrno)) { - LOGW("Error sending broadcast (%s)", strerror(errno)); + SLOGW("Error sending broadcast (%s)", strerror(errno)); } } pthread_mutex_unlock(&mClientsLock); @@ -224,7 +224,7 @@ void SocketListener::sendBroadcast(const char *msg) { for (i = mClients->begin(); i != mClients->end(); ++i) { if ((*i)->sendMsg(msg)) { - LOGW("Error sending broadcast (%s)", strerror(errno)); + SLOGW("Error sending broadcast (%s)", strerror(errno)); } } pthread_mutex_unlock(&mClientsLock); diff --git a/logcat/event.logtags b/logcat/event.logtags index 2459604b..5e6c256d 100644 --- a/logcat/event.logtags +++ b/logcat/event.logtags @@ -48,21 +48,11 @@ 2741 force_gc (reason|3) # This event is logged on each tickle 2742 tickle (authority|3) -# What happens in a sync operation (bytes sent and received, and -# operation details) -2743 sync_details (authority|3),(send|1|2),(recv|1|2),(details|3) # contacts aggregation: time and number of contacts. # count is negative for query phase, positive for merge phase 2747 contacts_aggregation (aggregation time|2|3), (count|1|1) -# This event is logged when GTalkService encounters important events -2800 gtalkservice (eventType|1) -# This event is logged for GTalk connection state changes. The status field is an int, but -# it really contains 4 separate values, each taking up a byte -# (eventType << 24) + (connection state << 16) + (connection error << 8) + network state -2801 gtalk_connection (status|1) - # Device boot timings. We include monotonic clock values because the # intrinsic event log times are wall-clock. # @@ -73,25 +63,6 @@ # ZygoteInit class preloading ends: 3030 boot_progress_preload_end (time|2|3) -# This event is logged when GTalk connection is closed. -# The status field is an int, but contains 2 different values, it's represented as -# -# (networkType << 8) + connection error -# -# the possible error values are -# -# no_error=0, no_network=1, connection_failed=2, unknown_host=3, auth_failed=4, -# auth_expired=5, heart_beat_timeout=6, server_error=7, server_reject_rate_limiting=8, unknown=10 -# -# duration is the connection duration. -4000 gtalk_conn_close (status|1),(duration|1) - -# This event is logged for GTalk heartbeat resets -# interval_and_nt contains both the heartbeat interval and the network type, It's represented as -# (networkType << 16) + interval -# interval is in seconds; network type can be 0 (mobile) or 1 (wifi); ip is the host ip addr. -4001 gtalk_heartbeat_reset (interval_and_nt|1),(ip|3) - # dvm_gc_info: LIST (LONG, LONG, LONG) # # First LONG: @@ -140,8 +111,6 @@ 75003 sqlite_mem_released (Memory released|1|2) 75004 sqlite_db_corrupt (Database file corrupt|3) -40000 checkin (Check in time|2|3) - 50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3) 50001 menu_opened (Menu type where 0 is options and 1 is context|1|5) @@ -171,46 +140,6 @@ # or supplicant died (2) 50025 wifi_supplicant_connection_state_changed (connected|1|5) -# PDP Context has a bad DNS address -50100 pdp_bad_dns_address (dns_address|3) - -# For data connection on PDP context, reached the data-out-without-data-in -# packet count that triggers a countdown to radio restart -50101 pdp_radio_reset_countdown_triggered (out_packet_count|1|1) - -# Radio restart - timed out with no incoming packets. -50102 pdp_radio_reset (out_packet_count|1|1) - -# PDP context reset - timed out with no incoming packets. -50103 pdp_context_reset (out_packet_count|1|1) - -# Reregister to data network - timed out with no incoming packets. -50104 pdp_reregister_network (out_packet_count|1|1) - -# PDP Setup failures -50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5) - -# 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 -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) - -# CDMA data network setup failure -50110 cdma_data_setup_failed (cause|1|5), (cid|1|5), (network_type|1|5) - -# CDMA data network drop -50111 cdma_data_drop (cid|1|5), (network_type|1|5) - -# GSM radio access technology switched -50112 gsm_rat_switched (cid|1|5), (network_from|1|5), (network_to|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) @@ -233,10 +162,6 @@ # 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) - # aggregation service 70200 aggregation (aggregation time|2|3) 70201 aggregation_test (field1|1|2),(field2|1|2),(field3|1|2),(field4|1|2),(field5|1|2) diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index 3130a1cc..5acdf777 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -24,12 +24,66 @@ #define DEFAULT_MAX_ROTATED_LOGS 4 static AndroidLogFormat * g_logformat; +static bool g_nonblock = false; +static int g_tail_lines = 0; /* logd prefixes records with a length field */ #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t) #define LOG_FILE_DIR "/dev/log/" +struct queued_entry_t { + union { + unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4))); + struct logger_entry entry __attribute__((aligned(4))); + }; + queued_entry_t* next; + + queued_entry_t() { + next = NULL; + } +}; + +static int cmp(queued_entry_t* a, queued_entry_t* b) { + int n = a->entry.sec - b->entry.sec; + if (n != 0) { + return n; + } + return a->entry.nsec - b->entry.nsec; +} + +struct log_device_t { + char* device; + bool binary; + int fd; + bool printed; + char label; + + queued_entry_t* queue; + log_device_t* next; + + log_device_t(char* d, bool b, char l) { + device = d; + binary = b; + label = l; + queue = NULL; + next = NULL; + printed = false; + } + + void enqueue(queued_entry_t* entry) { + if (this->queue == NULL) { + this->queue = entry; + } else { + queued_entry_t** e = &this->queue; + while (*e && cmp(entry, *e) >= 0) { + e = &((*e)->next); + } + entry->next = *e; + *e = entry; + } + } +}; namespace android { @@ -40,8 +94,8 @@ static int g_logRotateSizeKBytes = 0; // 0 means "no log rotat static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded" static int g_outFD = -1; static off_t g_outByteCount = 0; -static int g_isBinary = 0; static int g_printBinary = 0; +static int g_devCount = 0; static EventTagMap* g_eventTagMap = NULL; @@ -103,14 +157,14 @@ void printBinary(struct logger_entry *buf) } while (ret < 0 && errno == EINTR); } -static void processBuffer(struct logger_entry *buf) +static void processBuffer(log_device_t* dev, struct logger_entry *buf) { - int bytesWritten; + int bytesWritten = 0; int err; AndroidLogEntry entry; char binaryMsgBuf[1024]; - if (g_isBinary) { + if (dev->binary) { err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); //printf(">>> pri=%d len=%d msg='%s'\n", @@ -118,15 +172,27 @@ static void processBuffer(struct logger_entry *buf) } else { err = android_log_processLogBuffer(buf, &entry); } - if (err < 0) + if (err < 0) { goto error; + } - bytesWritten = android_log_filterAndPrintLogLine( - g_logformat, g_outFD, &entry); + if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) { + if (false && g_devCount > 1) { + binaryMsgBuf[0] = dev->label; + binaryMsgBuf[1] = ' '; + bytesWritten = write(g_outFD, binaryMsgBuf, 2); + if (bytesWritten < 0) { + perror("output error"); + exit(-1); + } + } - if (bytesWritten < 0) { - perror("output error"); - exit(-1); + bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry); + + if (bytesWritten < 0) { + perror("output error"); + exit(-1); + } } g_outByteCount += bytesWritten; @@ -142,36 +208,142 @@ error: return; } -static void readLogLines(int logfd) -{ - while (1) { - unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4))); - struct logger_entry *entry = (struct logger_entry *) buf; - int ret; +static void chooseFirst(log_device_t* dev, log_device_t** firstdev) { + for (*firstdev = NULL; dev != NULL; dev = dev->next) { + if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)) { + *firstdev = dev; + } + } +} - ret = read(logfd, entry, LOGGER_ENTRY_MAX_LEN); - if (ret < 0) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) - break; - perror("logcat read"); - exit(EXIT_FAILURE); +static void maybePrintStart(log_device_t* dev) { + if (!dev->printed) { + dev->printed = true; + if (g_devCount > 1 && !g_printBinary) { + char buf[1024]; + snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); + if (write(g_outFD, buf, strlen(buf)) < 0) { + perror("output error"); + exit(-1); + } } - else if (!ret) { - fprintf(stderr, "read: Unexpected EOF!\n"); - exit(EXIT_FAILURE); + } +} + +static void skipNextEntry(log_device_t* dev) { + maybePrintStart(dev); + queued_entry_t* entry = dev->queue; + dev->queue = entry->next; + delete entry; +} + +static void printNextEntry(log_device_t* dev) { + maybePrintStart(dev); + if (g_printBinary) { + printBinary(&dev->queue->entry); + } else { + processBuffer(dev, &dev->queue->entry); + } + skipNextEntry(dev); +} + +static void readLogLines(log_device_t* devices) +{ + log_device_t* dev; + int max = 0; + int ret; + int queued_lines = 0; + bool sleep = true; + + int result; + fd_set readset; + + for (dev=devices; dev; dev = dev->next) { + if (dev->fd > max) { + max = dev->fd; } + } + + while (1) { + do { + timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR. + FD_ZERO(&readset); + for (dev=devices; dev; dev = dev->next) { + FD_SET(dev->fd, &readset); + } + result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout); + } while (result == -1 && errno == EINTR); + + if (result >= 0) { + for (dev=devices; dev; dev = dev->next) { + if (FD_ISSET(dev->fd, &readset)) { + queued_entry_t* entry = new queued_entry_t(); + /* NOTE: driver guarantees we read exactly one full entry */ + ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN); + if (ret < 0) { + if (errno == EINTR) { + delete entry; + goto next; + } + if (errno == EAGAIN) { + delete entry; + break; + } + perror("logcat read"); + exit(EXIT_FAILURE); + } + else if (!ret) { + fprintf(stderr, "read: Unexpected EOF!\n"); + exit(EXIT_FAILURE); + } - /* NOTE: driver guarantees we read exactly one full entry */ + entry->entry.msg[entry->entry.len] = '\0'; - entry->msg[entry->len] = '\0'; + dev->enqueue(entry); + ++queued_lines; + } + } - if (g_printBinary) { - printBinary(entry); - } else { - (void) processBuffer(entry); + if (result == 0) { + // we did our short timeout trick and there's nothing new + // print everything we have and wait for more data + sleep = true; + while (true) { + chooseFirst(devices, &dev); + if (dev == NULL) { + break; + } + if (g_tail_lines == 0 || queued_lines <= g_tail_lines) { + printNextEntry(dev); + } else { + skipNextEntry(dev); + } + --queued_lines; + } + + // the caller requested to just dump the log and exit + if (g_nonblock) { + exit(0); + } + } else { + // print all that aren't the last in their list + sleep = false; + while (g_tail_lines == 0 || queued_lines > g_tail_lines) { + chooseFirst(devices, &dev); + if (dev == NULL || dev->queue->next == NULL) { + break; + } + if (g_tail_lines == 0) { + printNextEntry(dev); + } else { + skipNextEntry(dev); + } + --queued_lines; + } + } } +next: + ; } } @@ -228,6 +400,7 @@ static void show_help(const char *cmd) " brief process tag thread raw time threadtime long\n\n" " -c clear (flush) the entire log and exit\n" " -d dump the log and then exit (don't block)\n" + " -t <count> print only the most recent <count> lines (implies -d)\n" " -g get the size of the log's ring buffer and exit\n" " -b <buffer> request alternate ring buffer\n" " ('main' (default), 'radio', 'events')\n" @@ -275,16 +448,17 @@ static int setLogFormat(const char * formatString) extern "C" void logprint_run_tests(void); -int main (int argc, char **argv) +int main(int argc, char **argv) { - int logfd; int err; int hasSetLogFormat = 0; int clearLog = 0; int getLogSize = 0; int mode = O_RDONLY; - char *log_device = strdup("/dev/"LOGGER_LOG_MAIN); const char *forceFilters = NULL; + log_device_t* devices = NULL; + log_device_t* dev; + bool needBinary = false; g_logformat = android_log_format_new(); @@ -301,7 +475,7 @@ int main (int argc, char **argv) for (;;) { int ret; - ret = getopt(argc, argv, "cdgsQf:r::n:v:b:B"); + ret = getopt(argc, argv, "cdt:gsQf:r::n:v:b:B"); if (ret < 0) { break; @@ -319,21 +493,39 @@ int main (int argc, char **argv) break; case 'd': - mode |= O_NONBLOCK; + g_nonblock = true; + break; + + case 't': + g_nonblock = true; + g_tail_lines = atoi(optarg); break; case 'g': getLogSize = 1; break; - case 'b': - free(log_device); - log_device = - (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1); - strcpy(log_device, LOG_FILE_DIR); - strcat(log_device, optarg); + case 'b': { + char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1); + strcpy(buf, LOG_FILE_DIR); + strcat(buf, optarg); - android::g_isBinary = (strcmp(optarg, "events") == 0); + bool binary = strcmp(optarg, "events") == 0; + if (binary) { + needBinary = true; + } + + if (devices) { + dev = devices; + while (dev->next) { + dev = dev->next; + } + dev->next = new log_device_t(buf, binary, optarg[0]); + } else { + devices = new log_device_t(buf, binary, optarg[0]); + } + android::g_devCount++; + } break; case 'B': @@ -460,6 +652,19 @@ int main (int argc, char **argv) } } + if (!devices) { + devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm'); + android::g_devCount = 1; + int accessmode = + (mode & O_RDONLY) ? R_OK : 0 + | (mode & O_WRONLY) ? W_OK : 0; + // only add this if it's available + if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) { + devices->next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's'); + android::g_devCount++; + } + } + if (android::g_logRotateSizeKBytes != 0 && android::g_outputFileName == NULL ) { @@ -516,42 +721,52 @@ int main (int argc, char **argv) } } - logfd = open(log_device, mode); - if (logfd < 0) { - fprintf(stderr, "Unable to open log device '%s': %s\n", - log_device, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (clearLog) { - int ret; - ret = android::clearLog(logfd); - if (ret) { - perror("ioctl"); + dev = devices; + while (dev) { + dev->fd = open(dev->device, mode); + if (dev->fd < 0) { + fprintf(stderr, "Unable to open log device '%s': %s\n", + dev->device, strerror(errno)); exit(EXIT_FAILURE); } - return 0; - } - - if (getLogSize) { - int size, readable; - size = android::getLogSize(logfd); - if (size < 0) { - perror("ioctl"); - exit(EXIT_FAILURE); + if (clearLog) { + int ret; + ret = android::clearLog(dev->fd); + if (ret) { + perror("ioctl"); + exit(EXIT_FAILURE); + } } - readable = android::getLogReadableSize(logfd); - if (readable < 0) { - perror("ioctl"); - exit(EXIT_FAILURE); + if (getLogSize) { + int size, readable; + + size = android::getLogSize(dev->fd); + if (size < 0) { + perror("ioctl"); + exit(EXIT_FAILURE); + } + + readable = android::getLogReadableSize(dev->fd); + if (readable < 0) { + perror("ioctl"); + exit(EXIT_FAILURE); + } + + printf("%s: ring buffer is %dKb (%dKb consumed), " + "max entry is %db, max payload is %db\n", dev->device, + size / 1024, readable / 1024, + (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD); } - printf("ring buffer is %dKb (%dKb consumed), " - "max entry is %db, max payload is %db\n", - size / 1024, readable / 1024, - (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD); + dev = dev->next; + } + + if (getLogSize) { + return 0; + } + if (clearLog) { return 0; } @@ -559,10 +774,10 @@ int main (int argc, char **argv) //LOG_EVENT_LONG(11, 0x1122334455667788LL); //LOG_EVENT_STRING(0, "whassup, doc?"); - if (android::g_isBinary) + if (needBinary) android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE); - android::readLogLines(logfd); + android::readLogLines(devices); return 0; } diff --git a/rootdir/etc/vold.fstab b/rootdir/etc/vold.fstab index 16065e9f..4aad8dca 100644 --- a/rootdir/etc/vold.fstab +++ b/rootdir/etc/vold.fstab @@ -14,7 +14,7 @@ ## Example of a standard sdcard mount for the emulator / Dream # Mounts the first usable partition of the specified device -dev_mount sdcard /sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1 +dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1 ## Example of a dual card setup # dev_mount left_sdcard /sdcard1 auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1 diff --git a/rootdir/init.rc b/rootdir/init.rc index 34302618..63769f5a 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -12,7 +12,8 @@ loglevel 3 export ANDROID_ROOT /system export ANDROID_ASSETS /system/app export ANDROID_DATA /data - export EXTERNAL_STORAGE /sdcard + export EXTERNAL_STORAGE /mnt/sdcard + export ASEC_MOUNTPOINT /mnt/asec export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar # Backward compatibility @@ -20,15 +21,35 @@ loglevel 3 symlink /sys/kernel/debug /d # create mountpoints - mkdir /sdcard 0000 system system + mkdir /mnt 0775 root system + mkdir /mnt/sdcard 0000 system system + +# Create cgroup mount point for cpu accounting + mkdir /acct + mount cgroup none /acct cpuacct + mkdir /acct/uid + +# Backwards Compat - XXX: Going away in G* + symlink /mnt/sdcard /sdcard + mkdir /system mkdir /data 0771 system system mkdir /cache 0770 system cache mkdir /config 0500 root root -# create Android Secure External Cache mount tree - mkdir /asec 0700 system system - mount tmpfs tmpfs /asec mode=0755 + # Directory for putting things only root should see. + mkdir /mnt/secure 0700 root root + + # Directory for staging bindmounts + mkdir /mnt/secure/staging 0700 root root + + # Directory-target for where the secure container + # imagefile directory will be bind-mounted + mkdir /mnt/secure/asec 0700 root root + + # Secure container public mount points. + mkdir /mnt/asec 0700 root system + mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000 mount rootfs rootfs / ro remount @@ -104,6 +125,7 @@ loglevel 3 # create basic filesystem structure mkdir /data/misc 01771 system misc mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth + mkdir /data/misc/bluetooth 0770 system system mkdir /data/misc/keystore 0700 keystore keystore mkdir /data/misc/vpn 0770 system system mkdir /data/misc/systemkeys 0700 system system @@ -119,13 +141,6 @@ loglevel 3 mkdir /data/app 0771 system system mkdir /data/property 0700 root root - # STOPSHIP: Temporary Encrypted File Systems workaround - mkdir /data/secure 0771 system system - mkdir /data/secure/data 0771 system system - mkdir /data/secure/misc 01771 system misc - mkdir /data/securemisc/vpn 0770 system system - mkdir /data/secure/misc/vpn/profiles 0770 system system - # create dalvik-cache and double-check the perms mkdir /data/dalvik-cache 0771 system system chown system system /data/dalvik-cache @@ -264,17 +279,11 @@ service servicemanager /system/bin/servicemanager service vold /system/bin/vold socket vold stream 0660 root mount + ioprio be 2 service netd /system/bin/netd socket netd stream 0660 root system -service nexus /system/bin/nexus - socket nexus stream 0660 root system - disabled - -#service mountd /system/bin/mountd -# socket mountd stream 0660 root mount - service debuggerd /system/bin/debuggerd service ril-daemon /system/bin/rild @@ -291,12 +300,8 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys service media /system/bin/mediaserver user media - group system audio camera graphics inet net_bt net_bt_admin - -service bootsound /system/bin/playmp3 - user media - group audio - oneshot + group system audio camera graphics inet net_bt net_bt_admin net_raw + ioprio rt 4 service bootanim /system/bin/bootanimation user graphics diff --git a/run-as/Android.mk b/run-as/Android.mk new file mode 100644 index 00000000..326f5afe --- /dev/null +++ b/run-as/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= run-as.c package.c + +LOCAL_MODULE:= run-as + +LOCAL_FORCE_STATIC_EXECUTABLE := true + +LOCAL_STATIC_LIBRARIES := libc + +include $(BUILD_EXECUTABLE) diff --git a/run-as/NOTICE b/run-as/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/run-as/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/run-as/package.c b/run-as/package.c new file mode 100644 index 00000000..46f8239c --- /dev/null +++ b/run-as/package.c @@ -0,0 +1,471 @@ +/* +** +** Copyright 2010, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <private/android_filesystem_config.h> +#include "package.h" + +/* + * WARNING WARNING WARNING WARNING + * + * The following code runs as root on production devices, before + * the run-as command has dropped the uid/gid. Hence be very + * conservative and keep in mind the following: + * + * - Performance does not matter here, clarity and safety of the code + * does however. Documentation is a must. + * + * - Avoid calling C library functions with complex implementations + * like malloc() and printf(). You want to depend on simple system + * calls instead, which behaviour is not going to be altered in + * unpredictible ways by environment variables or system properties. + * + * - Do not trust user input and/or the filesystem whenever possible. + * + */ + +/* The file containing the list of installed packages on the system */ +#define PACKAGES_LIST_FILE "/data/system/packages.list" + +/* This should be large enough to hold the content of the package database file */ +#define PACKAGES_LIST_BUFFER_SIZE 8192 + +/* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen' + * This function always zero-terminate the destination buffer unless + * 'dstlen' is 0, even in case of overflow. + */ +static void +string_copy(char* dst, size_t dstlen, const char* src, size_t srclen) +{ + const char* srcend = src + srclen; + const char* dstend = dst + dstlen; + + if (dstlen == 0) + return; + + dstend--; /* make room for terminating zero */ + + while (dst < dstend && src < srcend && *src != '\0') + *dst++ = *src++; + + *dst = '\0'; /* zero-terminate result */ +} + +/* Read up to 'buffsize' bytes into 'buff' from the file + * named 'filename'. Return byte length on success, or -1 + * on error. + */ +static int +read_file(const char* filename, char* buff, size_t buffsize) +{ + int fd, len, old_errno; + + /* check the input buffer size */ + if (buffsize >= INT_MAX) { + errno = EINVAL; + return -1; + } + + /* open the file for reading */ + do { + fd = open(filename, O_RDONLY); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) + return -1; + + /* read the content */ + do { + len = read(fd, buff, buffsize); + } while (len < 0 && errno == EINTR); + + /* close the file, preserve old errno for better diagnostics */ + old_errno = errno; + close(fd); + errno = old_errno; + + return len; +} + +/* Check that a given directory: + * - exists + * - is owned by a given uid/gid + * - is a real directory, not a symlink + * - isn't readable or writable by others + * + * Return 0 on success, or -1 on error. + * errno is set to EINVAL in case of failed check. + */ +static int +check_directory_ownership(const char* path, uid_t uid) +{ + int ret; + struct stat st; + + do { + ret = lstat(path, &st); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + + /* must be a real directory, not a symlink */ + if (!S_ISDIR(st.st_mode)) + goto BAD; + + /* must be owned by specific uid/gid */ + if (st.st_uid != uid || st.st_gid != uid) + goto BAD; + + /* must not be readable or writable by others */ + if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0) + goto BAD; + + /* everything ok */ + return 0; + +BAD: + errno = EINVAL; + return -1; +} + +/* This function is used to check the data directory path for safety. + * We check that every sub-directory is owned by the 'system' user + * and exists and is not a symlink. We also check that the full directory + * path is properly owned by the user ID. + * + * Return 0 on success, -1 on error. + */ +int +check_data_path(const char* dataPath, uid_t uid) +{ + int nn; + + /* the path should be absolute */ + if (dataPath[0] != '/') { + errno = EINVAL; + return -1; + } + + /* look for all sub-paths, we do that by finding + * directory separators in the input path and + * checking each sub-path independently + */ + for (nn = 1; dataPath[nn] != '\0'; nn++) + { + char subpath[PATH_MAX]; + + /* skip non-separator characters */ + if (dataPath[nn] != '/') + continue; + + /* handle trailing separator case */ + if (dataPath[nn+1] == '\0') { + break; + } + + /* found a separator, check that dataPath is not too long. */ + if (nn >= (int)(sizeof subpath)) { + errno = EINVAL; + return -1; + } + + /* reject any '..' subpath */ + if (nn >= 3 && + dataPath[nn-3] == '/' && + dataPath[nn-2] == '.' && + dataPath[nn-1] == '.') { + errno = EINVAL; + return -1; + } + + /* copy to 'subpath', then check ownership */ + memcpy(subpath, dataPath, nn); + subpath[nn] = '\0'; + + if (check_directory_ownership(subpath, AID_SYSTEM) < 0) + return -1; + } + + /* All sub-paths were checked, now verify that the full data + * directory is owned by the application uid + */ + if (check_directory_ownership(dataPath, uid) < 0) + return -1; + + /* all clear */ + return 0; +} + +/* Return TRUE iff a character is a space or tab */ +static inline int +is_space(char c) +{ + return (c == ' ' || c == '\t'); +} + +/* Skip any space or tab character from 'p' until 'end' is reached. + * Return new position. + */ +static const char* +skip_spaces(const char* p, const char* end) +{ + while (p < end && is_space(*p)) + p++; + + return p; +} + +/* Skip any non-space and non-tab character from 'p' until 'end'. + * Return new position. + */ +static const char* +skip_non_spaces(const char* p, const char* end) +{ + while (p < end && !is_space(*p)) + p++; + + return p; +} + +/* Find the first occurence of 'ch' between 'p' and 'end' + * Return its position, or 'end' if none is found. + */ +static const char* +find_first(const char* p, const char* end, char ch) +{ + while (p < end && *p != ch) + p++; + + return p; +} + +/* Check that the non-space string starting at 'p' and eventually + * ending at 'end' equals 'name'. Return new position (after name) + * on success, or NULL on failure. + * + * This function fails is 'name' is NULL, empty or contains any space. + */ +static const char* +compare_name(const char* p, const char* end, const char* name) +{ + /* 'name' must not be NULL or empty */ + if (name == NULL || name[0] == '\0' || p == end) + return NULL; + + /* compare characters to those in 'name', excluding spaces */ + while (*name) { + /* note, we don't check for *p == '\0' since + * it will be caught in the next conditional. + */ + if (p >= end || is_space(*p)) + goto BAD; + + if (*p != *name) + goto BAD; + + p++; + name++; + } + + /* must be followed by end of line or space */ + if (p < end && !is_space(*p)) + goto BAD; + + return p; + +BAD: + return NULL; +} + +/* Parse one or more whitespace characters starting from '*pp' + * until 'end' is reached. Updates '*pp' on exit. + * + * Return 0 on success, -1 on failure. + */ +static int +parse_spaces(const char** pp, const char* end) +{ + const char* p = *pp; + + if (p >= end || !is_space(*p)) { + errno = EINVAL; + return -1; + } + p = skip_spaces(p, end); + *pp = p; + return 0; +} + +/* Parse a positive decimal number starting from '*pp' until 'end' + * is reached. Adjust '*pp' on exit. Return decimal value or -1 + * in case of error. + * + * If the value is larger than INT_MAX, -1 will be returned, + * and errno set to EOVERFLOW. + * + * If '*pp' does not start with a decimal digit, -1 is returned + * and errno set to EINVAL. + */ +static int +parse_positive_decimal(const char** pp, const char* end) +{ + const char* p = *pp; + int value = 0; + int overflow = 0; + + if (p >= end || *p < '0' || *p > '9') { + errno = EINVAL; + return -1; + } + + while (p < end) { + int ch = *p; + unsigned d = (unsigned)(ch - '0'); + int val2; + + if (d >= 10U) /* d is unsigned, no lower bound check */ + break; + + val2 = value*10 + (int)d; + if (val2 < value) + overflow = 1; + value = val2; + p++; + } + *pp = p; + + if (overflow) { + errno = EOVERFLOW; + value = -1; + } + return value; + +BAD: + *pp = p; + return -1; +} + +/* Read the system's package database and extract information about + * 'pkgname'. Return 0 in case of success, or -1 in case of error. + * + * If the package is unknown, return -1 and set errno to ENOENT + * If the package database is corrupted, return -1 and set errno to EINVAL + */ +int +get_package_info(const char* pkgName, PackageInfo *info) +{ + static char buffer[PACKAGES_LIST_BUFFER_SIZE]; + int buffer_len; + const char* p; + const char* buffer_end; + int result; + + info->uid = 0; + info->isDebuggable = 0; + info->dataDir[0] = '\0'; + + buffer_len = read_file(PACKAGES_LIST_FILE, buffer, sizeof buffer); + if (buffer_len < 0) + return -1; + + p = buffer; + buffer_end = buffer + buffer_len; + + /* expect the following format on each line of the control file: + * + * <pkgName> <uid> <debugFlag> <dataDir> + * + * where: + * <pkgName> is the package's name + * <uid> is the application-specific user Id (decimal) + * <debugFlag> is 1 if the package is debuggable, or 0 otherwise + * <dataDir> is the path to the package's data directory (e.g. /data/data/com.example.foo) + * + * The file is generated in com.android.server.PackageManagerService.Settings.writeLP() + */ + + while (p < buffer_end) { + /* find end of current line and start of next one */ + const char* end = find_first(p, buffer_end, '\n'); + const char* next = (end < buffer_end) ? end + 1 : buffer_end; + const char* q; + int uid, debugFlag; + + /* first field is the package name */ + p = compare_name(p, end, pkgName); + if (p == NULL) + goto NEXT_LINE; + + /* skip spaces */ + if (parse_spaces(&p, end) < 0) + goto BAD_FORMAT; + + /* second field is the pid */ + uid = parse_positive_decimal(&p, end); + if (uid < 0) + return -1; + + info->uid = (uid_t) uid; + + /* skip spaces */ + if (parse_spaces(&p, end) < 0) + goto BAD_FORMAT; + + /* third field is debug flag (0 or 1) */ + debugFlag = parse_positive_decimal(&p, end); + switch (debugFlag) { + case 0: + info->isDebuggable = 0; + break; + case 1: + info->isDebuggable = 1; + break; + default: + goto BAD_FORMAT; + } + + /* skip spaces */ + if (parse_spaces(&p, end) < 0) + goto BAD_FORMAT; + + /* fourth field is data directory path and must not contain + * spaces. + */ + q = skip_non_spaces(p, end); + if (q == p) + goto BAD_FORMAT; + + string_copy(info->dataDir, sizeof info->dataDir, p, q - p); + + /* Ignore the rest */ + return 0; + + NEXT_LINE: + p = next; + } + + /* the package is unknown */ + errno = ENOENT; + return -1; + +BAD_FORMAT: + errno = EINVAL; + return -1; +} diff --git a/run-as/package.h b/run-as/package.h new file mode 100644 index 00000000..852af063 --- /dev/null +++ b/run-as/package.h @@ -0,0 +1,41 @@ +/* +** +** Copyright 2010, 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 RUN_AS_PACKAGE_H +#define RUN_AS_PACKAGE_H + +#include <limits.h> +#include <sys/types.h> + +typedef enum { + PACKAGE_IS_DEBUGGABLE = 0, + PACKAGE_IS_NOT_DEBUGGABLE, + PACKAGE_IS_UNKNOWN, +} PackageStatus; + +typedef struct { + uid_t uid; + char isDebuggable; + char dataDir[PATH_MAX]; +} PackageInfo; + +/* see documentation in package.c for these functiosn */ + +extern int get_package_info(const char* packageName, PackageInfo* info); + +extern int check_data_path(const char* dataDir, uid_t uid); + +#endif /* RUN_AS_PACKAGE_H */ diff --git a/run-as/run-as.c b/run-as/run-as.c new file mode 100644 index 00000000..d2a44e1b --- /dev/null +++ b/run-as/run-as.c @@ -0,0 +1,178 @@ +/* +** +** Copyright 2010, 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. +*/ + +#define PROGNAME "run-as" +#define LOG_TAG PROGNAME + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <stdarg.h> + +#include <private/android_filesystem_config.h> +#include "package.h" + +/* + * WARNING WARNING WARNING WARNING + * + * This program runs as set-uid root on Android production devices. + * Be very conservative when modifying it to avoid any serious + * security issue. Keep in mind the following: + * + * - This program should only run for the 'root' or 'shell' users + * + * - Statically link against the C library, and avoid anything that + * is more complex than simple system calls until the uid/gid has + * been dropped to that of a normal user or you are sure to exit. + * + * This avoids depending on environment variables, system properties + * and other external factors that may affect the C library in + * unpredictable ways. + * + * - Do not trust user input and/or the filesystem whenever possible. + * + * Read README.TXT for more details. + * + * + * + * The purpose of this program is to run a command as a specific + * application user-id. Typical usage is: + * + * run-as <package-name> <command> <args> + * + * The 'run-as' binary is setuid, but will check the following: + * + * - that it is invoked from the 'shell' or 'root' user (abort otherwise) + * - that '<package-name>' is the name of an installed and debuggable package + * - that the package's data directory is well-formed (see package.c) + * + * If so, it will cd to the package's data directory, drop to the application's + * user id / group id then run the command there. + * + * This can be useful for a number of different things on production devices: + * + * - Allow application developers to look at their own applicative data + * during development. + * + * - Run the 'gdbserver' binary executable to allow native debugging + */ + +static void +usage(void) +{ + const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n"; + write(1, str, strlen(str)); + exit(1); +} + + +static void +panic(const char* format, ...) +{ + va_list args; + + fprintf(stderr, "%s: ", PROGNAME); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + exit(1); +} + + +int main(int argc, char **argv) +{ + const char* pkgname; + int myuid, uid, gid; + PackageInfo info; + + /* check arguments */ + if (argc < 2) + usage(); + + /* check userid of caller - must be 'shell' or 'root' */ + myuid = getuid(); + if (myuid != AID_SHELL && myuid != AID_ROOT) { + panic("only 'shell' or 'root' users can run this program\n"); + } + + /* retrieve package information from system */ + pkgname = argv[1]; + if (get_package_info(pkgname, &info) < 0) { + panic("Package '%s' is unknown\n", pkgname); + return 1; + } + + /* reject system packages */ + if (info.uid < AID_APP) { + panic("Package '%s' is not an application\n", pkgname); + return 1; + } + + /* reject any non-debuggable package */ + if (!info.isDebuggable) { + panic("Package '%s' is not debuggable\n", pkgname); + return 1; + } + + /* check that the data directory path is valid */ + if (check_data_path(info.dataDir, info.uid) < 0) { + panic("Package '%s' has corrupt installation\n", pkgname); + return 1; + } + + /* then move to it */ + { + int ret; + do { + ret = chdir(info.dataDir); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + panic("Could not cd to package's data directory: %s\n", strerror(errno)); + return 1; + } + } + + /* Ensure that we change all real/effective/saved IDs at the + * same time to avoid nasty surprises. + */ + uid = gid = info.uid; + if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { + panic("Permission denied\n"); + return 1; + } + + /* User specified command for exec. */ + if (argc >= 3 ) { + if (execvp(argv[2], argv+2) < 0) { + panic("exec failed for %s Error:%s\n", argv[2], strerror(errno)); + return -errno; + } + } + + /* Default exec shell. */ + execlp("/system/bin/sh", "sh", NULL); + + panic("exec failed\n"); + return 1; +} diff --git a/toolbox/Android.mk b/toolbox/Android.mk index 122a5445..a6114ac0 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -51,7 +51,8 @@ TOOLS := \ iftop \ id \ vmstat \ - nandread + nandread \ + ionice LOCAL_SRC_FILES:= \ toolbox.c \ diff --git a/toolbox/chown.c b/toolbox/chown.c index 13617db6..e9d108bf 100644 --- a/toolbox/chown.c +++ b/toolbox/chown.c @@ -35,19 +35,29 @@ int chown_main(int argc, char **argv) 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; + if (pw != NULL) { + uid = pw->pw_uid; + } else { + char* endptr; + uid = (int) strtoul(user, &endptr, 0); + if (endptr == user) { // no conversion + 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; + if (grp != NULL) { + gid = grp->gr_gid; + } else { + char* endptr; + gid = (int) strtoul(group, &endptr, 0); + if (endptr == group) { // no conversion + fprintf(stderr, "No such group '%s'\n", group); + return 10; + } } - gid = grp->gr_gid; } for (i = 2; i < argc; i++) { @@ -59,4 +69,3 @@ int chown_main(int argc, char **argv) return 0; } - diff --git a/toolbox/ionice.c b/toolbox/ionice.c new file mode 100644 index 00000000..4a182f2d --- /dev/null +++ b/toolbox/ionice.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include <cutils/iosched_policy.h> + +static char *classes[] = {"none", "rt", "be", "idle", NULL}; + +int ionice_main(int argc, char *argv[]) +{ + IoSchedClass clazz = IoSchedClass_NONE; + int ioprio = 0; + int pid; + + if(argc != 2 && argc != 4) { + fprintf(stderr, "usage: ionice <pid> [none|rt|be|idle] [prio]\n"); + return 1; + } + + if (!(pid = atoi(argv[1]))) { + fprintf(stderr, "Invalid pid specified\n"); + return 1; + } + + if (argc == 2) { + if (android_get_ioprio(pid, &clazz, &ioprio)) { + fprintf(stderr, "Failed to read priority (%s)\n", strerror(errno)); + return 1; + } + fprintf(stdout, "Pid %d, class %s (%d), prio %d\n", pid, classes[clazz], clazz, ioprio); + return 0; + } + + if (!strcmp(argv[2], "none")) { + clazz = IoSchedClass_NONE; + } else if (!strcmp(argv[2], "rt")) { + clazz = IoSchedClass_RT; + } else if (!strcmp(argv[2], "be")) { + clazz = IoSchedClass_BE; + } else if (!strcmp(argv[2], "idle")) { + clazz = IoSchedClass_IDLE; + } else { + fprintf(stderr, "Unsupported class '%s'\n", argv[2]); + return 1; + } + + ioprio = atoi(argv[3]); + + printf("Setting pid %d i/o class to %d, prio %d\n", pid, clazz, ioprio); + if (android_set_ioprio(pid, clazz, ioprio)) { + fprintf(stderr, "Failed to set priority (%s)\n", strerror(errno)); + return 1; + } + + return 0; +} diff --git a/toolbox/nandread.c b/toolbox/nandread.c index aacccdb2..96449730 100644 --- a/toolbox/nandread.c +++ b/toolbox/nandread.c @@ -8,7 +8,7 @@ #include <mtd/mtd-user.h> #include <sys/ioctl.h> -int test_empty(const char *buf, size_t size) +static int test_empty(const char *buf, size_t size) { while(size--) { if (*buf++ != 0xff) @@ -29,12 +29,14 @@ int nandread_main(int argc, char **argv) int ret; int verbose = 0; void *buffer; - loff_t pos, opos; + loff_t pos, opos, end, bpos; + loff_t start = 0, len = 0; int c; int i; int empty_pages = 0; int page_count = 0; int bad_block; + int rawmode = 0; uint32_t *oob_data; uint8_t *oob_fixed; size_t spare_size = 64; @@ -44,7 +46,7 @@ int nandread_main(int argc, char **argv) struct nand_ecclayout ecclayout; do { - c = getopt(argc, argv, "d:f:s:hv"); + c = getopt(argc, argv, "d:f:s:S:L:Rhv"); if (c == EOF) break; switch (c) { @@ -57,6 +59,15 @@ int nandread_main(int argc, char **argv) case 's': spare_size = atoi(optarg); break; + case 'S': + start = strtoll(optarg, NULL, 0); + break; + case 'L': + len = strtoll(optarg, NULL, 0); + break; + case 'R': + rawmode = 1; + break; case 'v': verbose++; break; @@ -65,6 +76,9 @@ int nandread_main(int argc, char **argv) " -d <dev> Read from <dev>\n" " -f <file> Write to <file>\n" " -s <size> Number of spare bytes in file (default 64)\n" + " -R Raw mode\n" + " -S <start> Start offset (default 0)\n" + " -L <len> Length (default 0)\n" " -v Print info\n" " -h Print help\n", argv[0]); return -1; @@ -129,7 +143,7 @@ int nandread_main(int argc, char **argv) oobbuf.length = mtdinfo.oobsize; oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize); - memset(oob_data, 0xff, spare_size); + memset(oob_data, 0xff, mtdinfo.oobsize + spare_size); oobbuf.ptr = (uint8_t *)oob_data + spare_size; ret = ioctl(fd, ECCGETLAYOUT, &ecclayout); @@ -160,21 +174,34 @@ int nandread_main(int argc, char **argv) printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks); } - for (pos = 0, opos = 0; pos < mtdinfo.size; pos += mtdinfo.writesize) { + if (rawmode) { + rawmode = mtdinfo.oobsize; + ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW); + if (ret) { + fprintf(stderr, "failed set raw mode for %s, %s\n", + devname, strerror(errno)); + return 1; + } + } + + end = len ? (start + len) : mtdinfo.size; + for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) { bad_block = 0; if (verbose > 3) printf("reading at %llx\n", pos); lseek64(fd, pos, SEEK_SET); - ret = read(fd, buffer, mtdinfo.writesize); + ret = read(fd, buffer, mtdinfo.writesize + rawmode); if (ret < (int)mtdinfo.writesize) { fprintf(stderr, "short read at %llx, %d\n", pos, ret); bad_block = 2; } - oobbuf.start = pos; - ret = ioctl(fd, MEMREADOOB, &oobbuf); - if (ret) { - fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret); - bad_block = 2; + if (!rawmode) { + oobbuf.start = pos; + ret = ioctl(fd, MEMREADOOB, &oobbuf); + if (ret) { + fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret); + bad_block = 2; + } } ret = ioctl(fd, ECCGETSTATS, &ecc); if (ret) { @@ -182,7 +209,8 @@ int nandread_main(int argc, char **argv) devname, strerror(errno)); return 1; } - ret = ioctl(fd, MEMGETBADBLOCK, &pos); + bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize; + ret = ioctl(fd, MEMGETBADBLOCK, &bpos); if (ret && errno != EOPNOTSUPP) { printf("badblock at %llx\n", pos); bad_block = 1; @@ -196,14 +224,16 @@ int nandread_main(int argc, char **argv) if (ecc.bbtblocks != last_ecc.bbtblocks) printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos); - oob_fixed = (uint8_t *)oob_data; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { - int len = ecclayout.oobfree[i].length; - if (oob_fixed + len > oobbuf.ptr) - len = oobbuf.ptr - oob_fixed; - if (len) { - memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len); - oob_fixed += len; + if (!rawmode) { + oob_fixed = (uint8_t *)oob_data; + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { + int len = ecclayout.oobfree[i].length; + if (oob_fixed + len > oobbuf.ptr) + len = oobbuf.ptr - oob_fixed; + if (len) { + memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len); + oob_fixed += len; + } } } diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c index 8e611c60..ff9e8446 100644 --- a/toolbox/newfs_msdos.c +++ b/toolbox/newfs_msdos.c @@ -414,11 +414,14 @@ newfs_msdos_main(int argc, char *argv[]) if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) { off_t delta; getdiskinfo(fd, fname, dtype, oflag, &bpb); + if (opt_s) { + bpb.bsec = opt_s; + } bpb.bsec -= (opt_ofs / bpb.bps); delta = bpb.bsec % bpb.spt; if (delta != 0) { - warnx("trim %d sectors to adjust to a multiple of %d", - (int)delta, bpb.spt); + warnx("trim %d sectors from %d to adjust to a multiple of %d", + (int)delta, bpb.bsec, bpb.spt); bpb.bsec -= delta; } if (bpb.spc == 0) { /* set defaults */ diff --git a/vold/Android.mk b/vold/Android.mk deleted file mode 100644 index 1288626b..00000000 --- a/vold/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -BUILD_VOLD := false -ifeq ($(BUILD_VOLD),true) - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - vold.c \ - cmd_dispatch.c \ - uevent.c \ - mmc.c \ - misc.c \ - blkdev.c \ - ums.c \ - geom_mbr_enc.c \ - volmgr.c \ - media.c \ - volmgr_vfat.c \ - volmgr_ext3.c \ - logwrapper.c \ - ProcessKiller.c\ - switch.c \ - format.c \ - devmapper.c - -LOCAL_MODULE:= vold - -LOCAL_C_INCLUDES := $(KERNEL_HEADERS) - -LOCAL_CFLAGS := - -LOCAL_SHARED_LIBRARIES := libcutils - -include $(BUILD_EXECUTABLE) - -endif # ifeq ($(BUILD_VOLD),true) diff --git a/vold/ProcessKiller.c b/vold/ProcessKiller.c deleted file mode 100644 index fc3eb370..00000000 --- a/vold/ProcessKiller.c +++ /dev/null @@ -1,222 +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. - */ - -/* -** mountd process killer -*/ - -#include "vold.h" - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <dirent.h> -#include <ctype.h> -#include <pwd.h> -#include <stdlib.h> -#include <poll.h> -#include <sys/stat.h> - - -static boolean ReadSymLink(const char* path, char* link) -{ - struct stat s; - int length; - - if (lstat(path, &s) < 0) - return false; - if ((s.st_mode & S_IFMT) != S_IFLNK) - return false; - - // we have a symlink - length = readlink(path, link, PATH_MAX - 1); - if (length <= 0) - return false; - link[length] = 0; - return true; -} - -static boolean PathMatchesMountPoint(const char* path, const char* mountPoint) -{ - int length = strlen(mountPoint); - if (length > 1 && strncmp(path, mountPoint, length) == 0) - { - // we need to do extra checking if mountPoint does not end in a '/' - if (mountPoint[length - 1] == '/') - return true; - // if mountPoint does not have a trailing slash, we need to make sure - // there is one in the path to avoid partial matches. - return (path[length] == 0 || path[length] == '/'); - } - - return false; -} - -static void GetProcessName(int pid, char buffer[PATH_MAX]) -{ - int fd; - sprintf(buffer, "/proc/%d/cmdline", pid); - fd = open(buffer, O_RDONLY); - if (fd < 0) { - strcpy(buffer, "???"); - } else { - int length = read(fd, buffer, PATH_MAX - 1); - buffer[length] = 0; - close(fd); - } -} - -static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint) -{ - DIR* dir; - struct dirent* de; - boolean fileOpen = false; - char path[PATH_MAX]; - char link[PATH_MAX]; - int parent_length; - - // compute path to process's directory of open files - sprintf(path, "/proc/%d/fd", pid); - dir = opendir(path); - if (!dir) - return false; - - // remember length of the path - parent_length = strlen(path); - // append a trailing '/' - path[parent_length++] = '/'; - - while ((de = readdir(dir)) != 0 && !fileOpen) { - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) - continue; - - // append the file name, after truncating to parent directory - path[parent_length] = 0; - strcat(path, de->d_name); - - if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint)) - { - char name[PATH_MAX]; - GetProcessName(pid, name); - LOG_ERROR("process %s (%d) has open file %s", name, pid, link); - fileOpen = true; - } - } - - closedir(dir); - return fileOpen; -} - -static boolean CheckFileMaps(int pid, const char* mountPoint) -{ - FILE* file; - char buffer[PATH_MAX + 100]; - boolean mapOpen = false; - - sprintf(buffer, "/proc/%d/maps", pid); - file = fopen(buffer, "r"); - if (!file) - return false; - - while (!mapOpen && fgets(buffer, sizeof(buffer), file)) - { - // skip to the path - const char* path = strchr(buffer, '/'); - if (path && PathMatchesMountPoint(path, mountPoint)) - { - char name[PATH_MAX]; - GetProcessName(pid, name); - LOG_ERROR("process %s (%d) has open file map for %s", name, pid, path); - mapOpen = true; - } - } - - fclose(file); - return mapOpen; -} - -static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message) -{ - char path[PATH_MAX]; - char link[PATH_MAX]; - - sprintf(path, "/proc/%d/%s", pid, name); - if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint)) - { - char name[PATH_MAX]; - GetProcessName(pid, name); - LOG_ERROR("process %s (%d) has %s in %s", name, pid, message, mountPoint); - return true; - } - else - return false; -} - -static int get_pid(const char* s) -{ - int result = 0; - while (*s) { - if (!isdigit(*s)) return -1; - result = 10 * result + (*s++ - '0'); - } - return result; -} - -// hunt down and kill processes that have files open on the given mount point -void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded) -{ - DIR* dir; - struct dirent* de; - - LOG_ERROR("KillProcessesWithOpenFiles %s", mountPoint); - dir = opendir("/proc"); - if (!dir) return; - - while ((de = readdir(dir)) != 0) - { - boolean killed = false; - // does the name look like a process ID? - int pid = get_pid(de->d_name); - if (pid == -1) continue; - - if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files - || CheckFileMaps(pid, mountPoint) // check for mmap() - || CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory - || CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot() - || CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path - ) - { - int i; - boolean hit = false; - - for (i = 0; i < num_excluded; i++) { - if (pid == excluded[i]) { - LOG_ERROR("I just need a little more TIME captain!"); - hit = true; - break; - } - } - - if (!hit) { - LOG_ERROR("Killing process %d", pid); - kill(pid, (sigkill ? SIGKILL : SIGTERM)); - } - } - } - - closedir(dir); -} diff --git a/vold/blkdev.c b/vold/blkdev.c deleted file mode 100644 index 33fed1b8..00000000 --- a/vold/blkdev.c +++ /dev/null @@ -1,329 +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 <dirent.h> -#include <errno.h> -#include <fcntl.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/mman.h> - -#include <linux/fs.h> -#include <linux/msdos_fs.h> - -#include "vold.h" -#include "blkdev.h" -#include "diskmbr.h" -#include "media.h" - -#define DEBUG_BLKDEV 0 - -static blkdev_list_t *list_root = NULL; - -static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major, - int minor, char *type, struct media *media); - -static int fat_valid_media(unsigned char media) -{ - return 0xf8 <= media || media == 0xf0; -} - -char *blkdev_get_devpath(blkdev_t *blk) -{ - char *dp = malloc(256); - sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor); - return dp; -} - -int blkdev_refresh(blkdev_t *blk) -{ - int fd = 0; - char *devpath = NULL; - unsigned char *block = NULL; - int i, rc; - - if (!(block = malloc(512))) - goto out; - - /* - * Get the device size - */ - devpath = blkdev_get_devpath(blk); - - 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 (%s)", strerror(errno)); - return -errno; - } - close(fd); - free(devpath); - - /* - * 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; - } - - free(devpath); - - 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 ((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 < NDOSPART; i++) { - 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++; - } - } else if (blk->type == blkdev_partition) { - struct dos_partition part; - int part_no; - - if (blk->media->media_type == media_mmc) - part_no = blk->minor % MMC_PARTS_PER_CARD -1; - else - part_no = blk->minor -1; - - if (part_no < NDOSPART) { - dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part); - blk->part_type = part.dp_typ; - } else { - LOGW("Skipping partition %d", part_no); - } - } - - out: - - 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 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); -} - -static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major, - 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!"); - return NULL; - } - - if (!(new = malloc(sizeof(blkdev_t)))) - return NULL; - - memset(new, 0, sizeof(blkdev_t)); - - if (!(list_entry = malloc(sizeof(struct blkdev_list)))) { - free (new); - return NULL; - } - list_entry->dev = new; - list_entry->next = NULL; - - if (!list_root) - list_root = list_entry; - else { - struct blkdev_list *list_scan = list_root; - while (list_scan->next) - list_scan = list_scan->next; - list_scan->next = list_entry; - } - - if (devpath) - new->devpath = strdup(devpath); - new->major = major; - new->minor = minor; - new->media = media; - new->nr_sec = 0xffffffff; - - if (disk) - new->disk = disk; - else - new->disk = new; // Note the self disk pointer - - /* Create device nodes */ - char nodepath[255]; - mode_t mode = 0660 | 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'", type); - new->type = blkdev_unknown; - } - - return new; -} - -void blkdev_destroy(blkdev_t *blkdev) -{ - struct blkdev_list *list_next; - - if (list_root->dev == blkdev) { - list_next = list_root->next; - free (list_root); - list_root = list_next; - } else { - struct blkdev_list *list_scan = list_root; - while (list_scan->next->dev != blkdev) - list_scan = list_scan -> next; - list_next = list_scan->next->next; - free(list_scan->next); - list_scan->next = list_next; - } - - if (blkdev->devpath) - free(blkdev->devpath); - - char nodepath[255]; - sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor); - unlink(nodepath); - - free(blkdev); -} - -blkdev_t *blkdev_lookup_by_path(char *devpath) -{ - struct blkdev_list *list_scan = list_root; - - while (list_scan) { - if (!strcmp(list_scan->dev->devpath, devpath)) - return list_scan->dev; - list_scan = list_scan->next; - } - return NULL; -} - -blkdev_t *blkdev_lookup_by_devno(int maj, int min) -{ - struct blkdev_list *list_scan = list_root; - - while (list_scan) { - if ((list_scan->dev->major == maj) && - (list_scan->dev->minor == min)) - return list_scan->dev; - list_scan = list_scan->next; - } - return NULL; -} - -/* - * Given a disk device, return the number of partitions which - * have yet to be processed. - */ -int blkdev_get_num_pending_partitions(blkdev_t *blk) -{ - struct blkdev_list *list_scan = list_root; - int num = blk->nr_parts; - - if (blk->type != blkdev_disk) - return -EINVAL; - - while (list_scan) { - if (list_scan->dev->type != blkdev_partition) - goto next; - - if (list_scan->dev->major != blk->major) - goto next; - - if (list_scan->dev->nr_sec != 0xffffffff && - list_scan->dev->devpath) { - num--; - } - next: - list_scan = list_scan->next; - } - return num; -} - diff --git a/vold/blkdev.h b/vold/blkdev.h deleted file mode 100644 index e789739e..00000000 --- a/vold/blkdev.h +++ /dev/null @@ -1,64 +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. - */ - -#ifndef _BLKDEV_H -#define _BLKDEV_H - -#include <sys/types.h> - -struct media; - -enum blk_type { blkdev_unknown, blkdev_disk, blkdev_partition }; - -struct blkdev { - char *devpath; - enum blk_type type; - struct media *media; - - // If type == blkdev_disk then nr_parts = number of partitions - int nr_parts; - - // If type == blkdev_partition then part_type = partition type - uint8_t part_type; - // If type == blkdev_partition - struct blkdev *disk; - - unsigned int nr_sec; - - int major; - int minor; -}; - -struct blkdev_list { - struct blkdev *dev; - struct blkdev_list *next; -}; - -typedef struct blkdev blkdev_t; -typedef struct blkdev_list blkdev_list_t; - -blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type); -blkdev_t *blkdev_create_pending_partition(blkdev_t *disk, char *dev_fspath, int major, int minor, struct media *media); -blkdev_t *blkdev_lookup_by_path(char *devpath); -blkdev_t *blkdev_lookup_by_devno(int maj, int min); -char *blkdev_get_devpath(blkdev_t *blk); - -void blkdev_destroy(blkdev_t *blk); - -int blkdev_get_num_pending_partitions(blkdev_t *blk); -int blkdev_refresh(blkdev_t *blk); -#endif diff --git a/vold/cmd_dispatch.c b/vold/cmd_dispatch.c deleted file mode 100644 index ab65fd96..00000000 --- a/vold/cmd_dispatch.c +++ /dev/null @@ -1,115 +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 <unistd.h> -#include <errno.h> - -#include "vold.h" -#include "cmd_dispatch.h" -#include "ums.h" -#include "volmgr.h" - -struct cmd_dispatch { - char *cmd; - int (* dispatch) (char *); -}; - -static void dispatch_cmd(char *cmd); -static int do_send_ums_status(char *cmd); -static int do_set_ums_enable(char *cmd); -static int do_mount_volume(char *cmd); -static int do_eject_media(char *cmd); -static 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_EJECT_MEDIA, do_eject_media }, - { VOLD_CMD_FORMAT_MEDIA, do_format_media }, - { NULL, NULL } -}; - -int process_framework_command(int socket) -{ - int rc; - char buffer[101]; - - if ((rc = read(socket, buffer, sizeof(buffer) -1)) < 0) { - LOGE("Unable to read framework command (%s)", strerror(errno)); - return -errno; - } else if (!rc) - return -ECONNRESET; - - int start = 0; - int i; - - buffer[rc] = 0; - - for (i = 0; i < rc; i++) { - if (buffer[i] == 0) { - dispatch_cmd(buffer + start); - start = i + 1; - } - } - return 0; -} - -static void dispatch_cmd(char *cmd) -{ - struct cmd_dispatch *c; - - LOG_VOL("dispatch_cmd(%s):", cmd); - - for (c = dispatch_table; c->cmd != NULL; c++) { - if (!strncmp(c->cmd, cmd, strlen(c->cmd))) { - c->dispatch(cmd); - return; - } - } - - LOGE("No cmd handlers defined for '%s'", cmd); -} - -static int do_send_ums_status(char *cmd) -{ - return ums_send_status(); -} - -static int do_set_ums_enable(char *cmd) -{ - if (!strcmp(cmd, VOLD_CMD_ENABLE_UMS)) - return volmgr_enable_ums(true); - - return volmgr_enable_ums(false); -} - -static int do_mount_volume(char *cmd) -{ - return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]); -} - -static int do_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 deleted file mode 100644 index f8ba6b3d..00000000 --- a/vold/cmd_dispatch.h +++ /dev/null @@ -1,31 +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. - */ - -#ifndef _CMD_DISPATCH_H -#define _CMD_DISPATCH_H - -// These must match the strings in java/android/android/os/UsbListener.java -#define VOLD_CMD_ENABLE_UMS "enable_ums" -#define VOLD_CMD_DISABLE_UMS "disable_ums" -#define VOLD_CMD_SEND_UMS_STATUS "send_ums_status" - -// these commands should contain a volume mount point after the colon -#define VOLD_CMD_MOUNT_VOLUME "mount_volume:" -#define VOLD_CMD_EJECT_MEDIA "eject_media:" -#define VOLD_CMD_FORMAT_MEDIA "format_media:" - -#endif diff --git a/vold/devmapper.c b/vold/devmapper.c deleted file mode 100644 index ef44c90e..00000000 --- a/vold/devmapper.c +++ /dev/null @@ -1,463 +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 <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 deleted file mode 100644 index 3d8cab36..00000000 --- a/vold/devmapper.h +++ /dev/null @@ -1,70 +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. - */ - -#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/diskmbr.h b/vold/diskmbr.h deleted file mode 100644 index 417e7caf..00000000 --- a/vold/diskmbr.h +++ /dev/null @@ -1,75 +0,0 @@ -/*- - * Copyright (c) 1987, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)disklabel.h 8.2 (Berkeley) 7/10/94 - * $FreeBSD: src/sys/sys/diskmbr.h,v 1.99.2.1 2005/01/31 23:26:56 imp Exp $ - */ - -#ifndef _SYS_DISKMBR_H_ -#define _SYS_DISKMBR_H_ - -#define DOSBBSECTOR 0 /* DOS boot block relative sector number */ -#define DOSPARTOFF 446 -#define DOSPARTSIZE 16 -#define NDOSPART 4 -#define NEXTDOSPART 32 -#define DOSMAGICOFFSET 510 -#define DOSMAGIC 0xAA55 - -#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */ -#define DOSPTYP_LINSWP 0x82 /* Linux swap partition */ -#define DOSPTYP_LINUX 0x83 /* Linux partition */ -#define DOSPTYP_PMBR 0xee /* GPT Protective MBR */ -#define DOSPTYP_EXT 5 /* DOS extended partition */ -#define DOSPTYP_EXTLBA 15 /* DOS extended partition */ - -struct dos_partition { - unsigned char dp_flag; /* bootstrap flags */ - unsigned char dp_shd; /* starting head */ - unsigned char dp_ssect; /* starting sector */ - unsigned char dp_scyl; /* starting cylinder */ - unsigned char dp_typ; /* partition type */ - unsigned char dp_ehd; /* end head */ - unsigned char dp_esect; /* end sector */ - unsigned char dp_ecyl; /* end cylinder */ - u_int32_t dp_start; /* absolute starting sector number */ - u_int32_t dp_size; /* partition size in sectors */ -}; -#ifdef CTASSERT -CTASSERT(sizeof (struct dos_partition) == DOSPARTSIZE); -#endif - -void dos_partition_dec(void const *pp, struct dos_partition *d); -void dos_partition_enc(void *pp, struct dos_partition *d); - -#define DPSECT(s) ((s) & 0x3f) /* isolate relevant bits of sector */ -#define DPCYL(c, s) ((c) + (((s) & 0xc0)<<2)) /* and those that are cylinder */ - -#define DIOCSMBR _IOW('M', 129, u_char[512]) - -#endif /* !_SYS_DISKMBR_H_ */ diff --git a/vold/format.c b/vold/format.c deleted file mode 100755 index c67b358d..00000000 --- a/vold/format.c +++ /dev/null @@ -1,117 +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 <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/newfs_msdos"; -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"; - if ((part->nr_sec * 512) <= (unsigned int) (1024*1024*1024*2)) - args[2] = "16"; - else - args[2] = "32"; - - args[3] = "-O"; - args[4] = "android"; - args[5] = devpath; - args[6] = NULL; - rc = logwrap(7, args, 1); - } 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, 1); - } - - 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 deleted file mode 100644 index 73cc0126..00000000 --- a/vold/format.h +++ /dev/null @@ -1,26 +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. - */ - -#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 deleted file mode 100644 index f1f8339b..00000000 --- a/vold/geom_mbr_enc.c +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2003 Poul-Henning Kamp - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Functions to encode or decode struct dos_partition into a bytestream - * of correct endianess and packing. These functions do no validation - * or sanity checking, they only pack/unpack the fields correctly. - * - * NB! This file must be usable both in kernel and userland. - */ - -#include <sys/types.h> -#include <sys/endian.h> - -#include "diskmbr.h" - -static __inline uint32_t __unused -le32dec(const void *buf) -{ - const uint8_t *p = (const uint8_t *)buf; - - return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); -} - -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) -{ - unsigned char const *p = pp; - - d->dp_flag = p[0]; - d->dp_shd = p[1]; - d->dp_ssect = p[2]; - d->dp_scyl = p[3]; - d->dp_typ = p[4]; - d->dp_ehd = p[5]; - d->dp_esect = p[6]; - d->dp_ecyl = p[7]; - d->dp_start = le32dec(p + 8); - d->dp_size = le32dec(p + 12); -} - -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/logwrapper.c b/vold/logwrapper.c deleted file mode 100644 index 8da4892c..00000000 --- a/vold/logwrapper.c +++ /dev/null @@ -1,167 +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 <string.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> - -#include "private/android_filesystem_config.h" -#include "cutils/log.h" - -int parent(const char *tag, int parent_read) { - int status; - char buffer[4096]; - - int a = 0; // start index of unprocessed data - int b = 0; // end index of unprocessed data - int sz; - while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) { - - sz += b; - // Log one line at a time - for (b = 0; b < sz; b++) { - if (buffer[b] == '\r') { - buffer[b] = '\0'; - } else if (buffer[b] == '\n') { - buffer[b] = '\0'; - - LOG(LOG_INFO, tag, "%s", &buffer[a]); - a = b + 1; - } - } - - if (a == 0 && b == sizeof(buffer) - 1) { - // buffer is full, flush - buffer[b] = '\0'; - LOG(LOG_INFO, tag, &buffer[a]); - b = 0; - } else if (a != b) { - // Keep left-overs - b -= a; - memmove(buffer, &buffer[a], b); - a = 0; - } else { - a = 0; - b = 0; - } - - } - // Flush remaining data - if (a != b) { - buffer[b] = '\0'; - LOG(LOG_INFO, tag, &buffer[a]); - } - status = 0xAAAA; - if (wait(&status) != -1) { // Wait for child - if (WIFEXITED(status)) { - LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag, - WEXITSTATUS(status)); - return WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) - LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag, - WTERMSIG(status)); - else if (WIFSTOPPED(status)) - LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag, - WSTOPSIG(status)); - } else - LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag, - strerror(errno), errno); - return -EAGAIN; -} - -void child(int argc, char* argv[]) { - // create null terminated argv_child array - char* argv_child[argc + 1]; - memcpy(argv_child, argv, argc * sizeof(char *)); - argv_child[argc] = NULL; - - // XXX: PROTECT FROM VIKING KILLER - if (execv(argv_child[0], argv_child)) { - LOG(LOG_ERROR, "logwrapper", - "executing %s failed: %s", argv_child[0], strerror(errno)); - exit(-1); - } -} - -int logwrap(int argc, char* argv[], pid_t *childPid, int background) -{ - pid_t pid; - - int parent_ptty; - int child_ptty; - char *child_devname = NULL; - - /* Use ptty instead of socketpair so that STDOUT is not buffered */ - parent_ptty = open("/dev/ptmx", O_RDWR); - if (parent_ptty < 0) { - LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty"); - return -errno; - } - - if (grantpt(parent_ptty) || unlockpt(parent_ptty) || - ((child_devname = (char*)ptsname(parent_ptty)) == 0)) { - LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx"); - return -1; - } - - pid = fork(); - if (pid < 0) { - 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"); - return -errno; - } - - // redirect stdout and stderr - close(parent_ptty); - dup2(child_ptty, 1); - dup2(child_ptty, 2); - close(child_ptty); - - if (background) { - int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY); - - if (fd >=0 ) { - char text[64]; - - sprintf(text, "%d", getpid()); - if (write(fd, text, strlen(text)) < 0) { - LOG(LOG_WARN, "logwrapper", - "Unable to background process (%s)", strerror(errno)); - close(fd); - } - close(fd); - } else { - LOG(LOG_WARN, "logwrapper", - "Unable to background process (%s)", strerror(errno)); - } - } - - child(argc, argv); - } else { - return parent(argv[0], parent_ptty); - } - - return 0; -} diff --git a/vold/logwrapper.h b/vold/logwrapper.h deleted file mode 100644 index bf28aae3..00000000 --- a/vold/logwrapper.h +++ /dev/null @@ -1,23 +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. - */ - -#ifndef _LOGWRAPPER_H -#define _LOGWRAPPER_H - -#include <stdlib.h> -int logwrap(int argc, char* argv[], int background); -#endif diff --git a/vold/media.c b/vold/media.c deleted file mode 100644 index db42a3e6..00000000 --- a/vold/media.c +++ /dev/null @@ -1,163 +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 <dirent.h> -#include <errno.h> - -#include <sys/types.h> - -#include "vold.h" -#include "media.h" - -static media_list_t *list_root = NULL; - -media_t *media_create(char *devpath, char *name, char *serial, media_type_t type) -{ - media_list_t *list_entry; - media_t *new; - - if (!(new = malloc(sizeof(media_t)))) - return NULL; - - memset(new, 0, sizeof(media_t)); - - if (!(list_entry = malloc(sizeof(media_list_t)))) { - free(new); - return NULL; - } - list_entry->media = new; - list_entry->next = NULL; - - if (!list_root) - list_root = list_entry; - else { - media_list_t *list_scan = list_root; - while(list_scan->next) - list_scan = list_scan->next; - list_scan->next = list_entry; - } - - new->devpath = strdup(devpath); - new->name = strdup(name); - if (!serial) - new->serial = 0; - else - new->serial = strtoul(serial, NULL, 0); - - new->media_type = type; - - return new; -} - -void media_destroy(media_t *media) -{ - media_list_t *list_next; - - if (list_root->media == media) { - list_next = list_root->next; - free(list_root); - list_root = list_next; - } else { - media_list_t *list_scan = list_root; - while (list_scan->next->media != media) - list_scan = list_scan -> next; - list_next = list_scan->next->next; - free(list_scan->next); - list_scan->next = list_next; - } - - free(media->devpath); - free(media->name); - - while(media->devs) - media_remove_blkdev(media, media->devs->dev); - free(media); -} - -media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match) -{ - media_list_t *list_scan = list_root; - - while (list_scan) { - if (fuzzy_match) { - if (!strncmp(list_scan->media->devpath, devpath, strlen(devpath))) - return list_scan->media; - } else { - if (!strcmp(list_scan->media->devpath, devpath)) - return list_scan->media; - } - list_scan = list_scan->next; - } -#if DEBUG_MEDIA - LOG_VOL("media_lookup_by_path(): No media found @ %s", devpath); -#endif - return NULL; -} - -int media_add_blkdev(media_t *card, blkdev_t *dev) -{ - blkdev_list_t *list_entry; - - if (!(list_entry = malloc(sizeof(blkdev_list_t)))) - return -ENOMEM; - - list_entry->next = NULL; - list_entry->dev = dev; - if (!card->devs) - card->devs = list_entry; - else { - blkdev_list_t *scan = card->devs; - - while(scan->next) - scan = scan->next; - - scan->next = list_entry; - } - return 0; -} - -void media_remove_blkdev(media_t *card, blkdev_t *dev) -{ - if (card->devs->dev == dev) - card->devs = card->devs->next; - else { - blkdev_list_t *scan = card->devs; - while (scan->next->dev != dev) - scan = scan -> next; - blkdev_list_t *next = scan->next->next; - free(scan->next); - scan->next = next; - } -} - -media_t *media_lookup_by_dev(blkdev_t *dev) -{ - media_list_t *media_scan = list_root; - - while (media_scan) { - blkdev_list_t *blk_scan = media_scan->media->devs; - while (blk_scan) { - if (blk_scan->dev == dev) - return media_scan->media; - blk_scan = blk_scan->next; - } - media_scan = media_scan->next; - } - return NULL; -} diff --git a/vold/media.h b/vold/media.h deleted file mode 100644 index 6fd8b843..00000000 --- a/vold/media.h +++ /dev/null @@ -1,57 +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. - */ - -#ifndef _MEDIA_H -#define _MEDIA_H - -#include <sys/types.h> - -#include "blkdev.h" - -typedef enum media_type { - media_unknown, - media_mmc, - media_devmapper, -} media_type_t; - -/* - * max 8 partitions per card - */ -#define MMC_PARTS_PER_CARD (1<<3) -#define ALIGN_MMC_MINOR(min) (min / MMC_PARTS_PER_CARD * MMC_PARTS_PER_CARD) - -typedef struct media { - char *devpath; - char *name; - uint32_t serial; - media_type_t media_type; - - blkdev_list_t *devs; -} media_t; - -typedef struct media_list { - media_t *media; - struct media_list *next; -} media_list_t; - -media_t *media_create(char *devpath, char *name, char *serial, enum media_type); -media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match); -media_t *media_lookup_by_dev(blkdev_t *dev); -void media_destroy(media_t *media); -int media_add_blkdev(media_t *media, blkdev_t *dev); -void media_remove_blkdev(media_t *media, blkdev_t *dev); -#endif diff --git a/vold/misc.c b/vold/misc.c deleted file mode 100644 index 0f8f61e0..00000000 --- a/vold/misc.c +++ /dev/null @@ -1,91 +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 <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <malloc.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -void *read_file(char *filename, ssize_t *_size) -{ - int ret, fd; - struct stat sb; - ssize_t size; - void *buffer = NULL; - - /* open the file */ - fd = open(filename, O_RDONLY); - if (fd < 0) - return NULL; - - /* find out how big it is */ - if (fstat(fd, &sb) < 0) - goto bail; - size = sb.st_size; - - /* allocate memory for it to be read into */ - buffer = malloc(size); - if (!buffer) - goto bail; - - /* slurp it into our buffer */ - ret = read(fd, buffer, size); - if (ret != size) - goto bail; - - /* let the caller know how big it is */ - *_size = size; - -bail: - close(fd); - return buffer; -} -char *truncate_sysfs_path(char *path, int num_elements_to_remove, char *buffer, int buffer_size) -{ - int i; - - strncpy(buffer, path, buffer_size); - - for (i = 0; i < num_elements_to_remove; i++) { - char *p = &buffer[strlen(buffer)-1]; - - for (p = &buffer[strlen(buffer) -1]; *p != '/'; p--); - *p = '\0'; - } - - return buffer; -} - -char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var) -{ - char filename[255]; - char *p; - ssize_t sz; - - snprintf(filename, sizeof(filename), "/sys%s/%s", devpath, var); - p = read_file(filename, &sz); - p[(strlen(p) - 1)] = '\0'; - strncpy(buffer, p, maxlen); - free(p); - return buffer; -} - diff --git a/vold/mmc.c b/vold/mmc.c deleted file mode 100644 index d90845d3..00000000 --- a/vold/mmc.c +++ /dev/null @@ -1,301 +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 <dirent.h> -#include <errno.h> - -#include <sys/types.h> - -#include "vold.h" -#include "mmc.h" -#include "media.h" -#include "diskmbr.h" /* for NDOSPART */ - -#define DEBUG_BOOTSTRAP 0 - -static int mmc_bootstrap_controller(char *sysfs_path); -static int mmc_bootstrap_card(char *sysfs_path); -static int mmc_bootstrap_block(char *devpath); -static int mmc_bootstrap_mmcblk(char *devpath); -static int mmc_bootstrap_mmcblk_partition(char *devpath); - -/* - * Bootstrap our mmc information. - */ -int mmc_bootstrap() -{ - DIR *d; - struct dirent *de; - - if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) { - LOG_ERROR("Unable to open '%s' (%s)", SYSFS_CLASS_MMC_PATH, - strerror(errno)); - return -errno; - } - - while ((de = readdir(d))) { - char tmp[255]; - - if (de->d_name[0] == '.') - continue; - - sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name); - if (mmc_bootstrap_controller(tmp)) { - LOG_ERROR("Error bootstrapping controller '%s' (%s)", tmp, - strerror(errno)); - } - } - - closedir(d); - - return 0; -} - -static int mmc_bootstrap_controller(char *sysfs_path) -{ - DIR *d; - struct dirent *de; - -#if DEBUG_BOOTSTRAP - LOG_VOL("bootstrap_controller(%s):", sysfs_path); -#endif - if (!(d = opendir(sysfs_path))) { - LOG_ERROR("Unable to open '%s' (%s)", sysfs_path, strerror(errno)); - return -errno; - } - - while ((de = readdir(d))) { - char tmp[255]; - - if (de->d_name[0] == '.') - continue; - - if ((!strcmp(de->d_name, "uevent")) || - (!strcmp(de->d_name, "subsystem")) || - (!strcmp(de->d_name, "device")) || - (!strcmp(de->d_name, "power"))) { - continue; - } - - sprintf(tmp, "%s/%s", sysfs_path, de->d_name); - - if (mmc_bootstrap_card(tmp) < 0) - LOG_ERROR("Error bootstrapping card '%s' (%s)", tmp, strerror(errno)); - } // while - - closedir(d); - return 0; -} - -static int mmc_bootstrap_card(char *sysfs_path) -{ - char saved_cwd[255]; - char new_cwd[255]; - char *devpath; - char *uevent_params[4]; - char *p; - char filename[255]; - char tmp[255]; - ssize_t sz; - -#if DEBUG_BOOTSTRAP - LOG_VOL("bootstrap_card(%s):", 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("Error getting working dir path"); - return -errno; - } - - if (chdir(sysfs_path) < 0) { - LOGE("Unable to chdir to %s (%s)", sysfs_path, strerror(errno)); - return -errno; - } - - if (!getcwd(new_cwd, sizeof(new_cwd))) { - LOGE("Buffer too small for device path"); - return -errno; - } - - if (chdir(saved_cwd) < 0) { - LOGE("Unable to restore working dir"); - return -errno; - } - - devpath = &new_cwd[4]; // Skip over '/sys' - - /* - * Collect parameters so we can simulate a UEVENT - */ - sprintf(tmp, "DEVPATH=%s", devpath); - uevent_params[0] = (char *) strdup(tmp); - - sprintf(filename, "/sys%s/type", devpath); - p = read_file(filename, &sz); - p[strlen(p) - 1] = '\0'; - sprintf(tmp, "MMC_TYPE=%s", p); - free(p); - uevent_params[1] = (char *) strdup(tmp); - - sprintf(filename, "/sys%s/name", devpath); - p = read_file(filename, &sz); - if (!p) { - LOGE("Unable to read MMC name: %s", filename); - return -errno; - } - p[strlen(p) - 1] = '\0'; - sprintf(tmp, "MMC_NAME=%s", p); - free(p); - uevent_params[2] = (char *) strdup(tmp); - - uevent_params[3] = (char *) NULL; - - if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) { - LOGE("Error simulating uevent (%s)", strerror(errno)); - return -errno; - } - - /* - * Check for block drivers - */ - char block_devpath[255]; - sprintf(tmp, "%s/block", devpath); - sprintf(filename, "/sys%s/block", devpath); - if (!access(filename, F_OK)) { - if (mmc_bootstrap_block(tmp)) { - LOGE("Error bootstrapping block @ %s", tmp); - } - } - - return 0; -} - -static int mmc_bootstrap_block(char *devpath) -{ - char blockdir_path[255]; - DIR *d; - struct dirent *de; - -#if DEBUG_BOOTSTRAP - LOG_VOL("mmc_bootstrap_block(%s):", devpath); -#endif - - sprintf(blockdir_path, "/sys%s", devpath); - - if (!(d = opendir(blockdir_path))) { - LOGE("Failed to opendir %s", devpath); - return -errno; - } - - while ((de = readdir(d))) { - char tmp[255]; - - if (de->d_name[0] == '.') - continue; - sprintf(tmp, "%s/%s", devpath, de->d_name); - if (mmc_bootstrap_mmcblk(tmp)) - LOGE("Error bootstraping mmcblk @ %s", tmp); - } - closedir(d); - return 0; -} - -static int mmc_bootstrap_mmcblk(char *devpath) -{ - char *mmcblk_devname; - int part_no; - int rc; - -#if DEBUG_BOOTSTRAP - LOG_VOL("mmc_bootstrap_mmcblk(%s):", devpath); -#endif - - if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) { - LOGE("Error bootstrapping mmcblk partition '%s'", devpath); - return rc; - } - - for (mmcblk_devname = &devpath[strlen(devpath)]; - *mmcblk_devname != '/'; mmcblk_devname--); - mmcblk_devname++; - - for (part_no = 1; part_no <= NDOSPART; part_no++) { - char part_file[255]; - sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no); - if (!access(part_file, F_OK)) { - char part_devpath[255]; - - sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no); - if (mmc_bootstrap_mmcblk_partition(part_devpath)) - LOGE("Error bootstrapping mmcblk partition '%s'", part_devpath); - } - } - - return 0; -} - -static int mmc_bootstrap_mmcblk_partition(char *devpath) -{ - char filename[255]; - char *uevent_buffer; - ssize_t sz; - char *uevent_params[5]; - char tmp[255]; - FILE *fp; - char line[255]; - -#if DEBUG_BOOTSTRAP - LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):", devpath); -#endif - - sprintf(tmp, "DEVPATH=%s", devpath); - uevent_params[0] = strdup(tmp); - - sprintf(filename, "/sys%s/uevent", devpath); - if (!(fp = fopen(filename, "r"))) { - LOGE("Unable to open '%s' (%s)", filename, strerror(errno)); - return -errno; - } - - while (fgets(line, sizeof(line), fp)) { - line[strlen(line)-1] = 0; - if (!strncmp(line, "DEVTYPE=", 8)) - uevent_params[1] = strdup(line); - else if (!strncmp(line, "MAJOR=",6)) - uevent_params[2] = strdup(line); - else if (!strncmp(line, "MINOR=",6)) - uevent_params[3] = strdup(line); - } - fclose(fp); - - if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) { - LOGE("mmcblk uevent missing required params"); - return -1; - } - uevent_params[4] = '\0'; - - if (simulate_uevent("block", devpath, "add", uevent_params) < 0) { - LOGE("Error simulating uevent (%s)", strerror(errno)); - return -errno; - } - return 0; -} diff --git a/vold/mmc.h b/vold/mmc.h deleted file mode 100644 index 5a5d184e..00000000 --- a/vold/mmc.h +++ /dev/null @@ -1,23 +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. - */ - -#ifndef _MMC_H -#define _MMC_H - -#define SYSFS_CLASS_MMC_PATH "/sys/class/mmc_host" - -#endif diff --git a/vold/switch.c b/vold/switch.c deleted file mode 100644 index d8dab432..00000000 --- a/vold/switch.c +++ /dev/null @@ -1,124 +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 <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' (%s)", SYSFS_CLASS_SWITCH_PATH, - strerror(errno)); - 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' (%s)", tmp, - strerror(errno)); - } - } - - 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/uevent.c b/vold/uevent.c deleted file mode 100644 index dc15d80d..00000000 --- a/vold/uevent.c +++ /dev/null @@ -1,447 +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 <string.h> -#include <stdlib.h> -#include <errno.h> - -#include <sys/types.h> -#include <sys/socket.h> - -#include "vold.h" -#include "uevent.h" -#include "mmc.h" -#include "blkdev.h" -#include "volmgr.h" -#include "media.h" - -#define DEBUG_UEVENT 0 - -#define UEVENT_PARAMS_MAX 32 - -enum uevent_action { action_add, action_remove, action_change }; - -struct uevent { - char *path; - enum uevent_action action; - char *subsystem; - char *param[UEVENT_PARAMS_MAX]; - unsigned int seqnum; -}; - -struct uevent_dispatch { - char *subsystem; - int (* dispatch) (struct uevent *); -}; - -static void dump_uevent(struct uevent *); -static int dispatch_uevent(struct uevent *event); -static void free_uevent(struct uevent *event); -static char *get_uevent_param(struct uevent *event, char *param_name); - -static int handle_powersupply_event(struct uevent *event); -static int handle_switch_event(struct uevent *); -static int handle_battery_event(struct uevent *); -static int handle_mmc_event(struct uevent *); -static int handle_block_event(struct uevent *); -static int handle_bdi_event(struct uevent *); -static void _cb_blkdev_ok_to_destroy(blkdev_t *dev); - -static struct uevent_dispatch dispatch_table[] = { - { "switch", handle_switch_event }, - { "battery", handle_battery_event }, - { "mmc", handle_mmc_event }, - { "block", handle_block_event }, - { "bdi", handle_bdi_event }, - { "power_supply", handle_powersupply_event }, - { NULL, NULL } -}; - -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 :) - int count; - char *s = buffer; - char *end; - struct uevent *event; - int param_idx = 0; - int i; - int first = 1; - int rc = 0; - - if ((count = recv(socket, buffer, sizeof(buffer), 0)) < 0) { - LOGE("Error receiving uevent (%s)", strerror(errno)); - return -errno; - } - - if (!(event = malloc(sizeof(struct uevent)))) { - LOGE("Error allocating memory (%s)", strerror(errno)); - return -errno; - } - - memset(event, 0, sizeof(struct uevent)); - - end = s + count; - while (s < end) { - if (first) { - char *p; - for (p = s; *p != '@'; p++); - p++; - event->path = strdup(p); - first = 0; - } else { - if (!strncmp(s, "ACTION=", strlen("ACTION="))) { - char *a = s + strlen("ACTION="); - - if (!strcmp(a, "add")) - event->action = action_add; - else if (!strcmp(a, "change")) - event->action = action_change; - else if (!strcmp(a, "remove")) - event->action = action_remove; - } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM="))) - event->seqnum = atoi(s + strlen("SEQNUM=")); - else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM="))) - event->subsystem = strdup(s + strlen("SUBSYSTEM=")); - else - event->param[param_idx++] = strdup(s); - } - s+= strlen(s) + 1; - } - - rc = dispatch_uevent(event); - - free_uevent(event); - return rc; -} - -int simulate_uevent(char *subsys, char *path, char *action, char **params) -{ - struct uevent *event; - char tmp[255]; - int i, rc; - - if (!(event = malloc(sizeof(struct uevent)))) { - LOGE("Error allocating memory (%s)", strerror(errno)); - return -errno; - } - - memset(event, 0, sizeof(struct uevent)); - - event->subsystem = strdup(subsys); - - if (!strcmp(action, "add")) - event->action = action_add; - else if (!strcmp(action, "change")) - event->action = action_change; - else if (!strcmp(action, "remove")) - event->action = action_remove; - else { - LOGE("Invalid action '%s'", action); - return -1; - } - - event->path = strdup(path); - - for (i = 0; i < UEVENT_PARAMS_MAX; i++) { - if (!params[i]) - break; - event->param[i] = strdup(params[i]); - } - - rc = dispatch_uevent(event); - free_uevent(event); - return rc; -} - -static int dispatch_uevent(struct uevent *event) -{ - int i; - -#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", event->subsystem); -#endif - return 0; -} - -static void dump_uevent(struct uevent *event) -{ - int i; - - LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s", - event->seqnum, event->subsystem, event->action, event->path); - for (i = 0; i < UEVENT_PARAMS_MAX; i++) { - if (!event->param[i]) - break; - LOG_VOL("%s", event->param[i]); - } -} - -static void free_uevent(struct uevent *event) -{ - int i; - free(event->path); - free(event->subsystem); - for (i = 0; i < UEVENT_PARAMS_MAX; i++) { - if (!event->param[i]) - break; - free(event->param[i]); - } - free(event); -} - -static char *get_uevent_param(struct uevent *event, char *param_name) -{ - int i; - - for (i = 0; i < UEVENT_PARAMS_MAX; i++) { - if (!event->param[i]) - break; - if (!strncmp(event->param[i], param_name, strlen(param_name))) - return &event->param[i][strlen(param_name) + 1]; - } - - LOGE("get_uevent_param(): No parameter '%s' found", param_name); - return NULL; -} - -/* - * --------------- - * Uevent Handlers - * --------------- - */ - -static int handle_powersupply_event(struct uevent *event) -{ - char *ps_type = get_uevent_param(event, "POWER_SUPPLY_TYPE"); - - if (!strcasecmp(ps_type, "battery")) { - char *ps_cap = get_uevent_param(event, "POWER_SUPPLY_CAPACITY"); - int capacity = atoi(ps_cap); - - if (capacity < 5) - low_batt = true; - else - low_batt = false; - volmgr_safe_mode(low_batt || door_open); - } - return 0; -} - -static int handle_switch_event(struct uevent *event) -{ - char *name = get_uevent_param(event, "SWITCH_NAME"); - char *state = get_uevent_param(event, "SWITCH_STATE"); - - - if (!strcmp(name, "usb_mass_storage")) { - if (!strcmp(state, "online")) { - ums_hostconnected_set(true); - } else { - ums_hostconnected_set(false); - 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); - } - - return 0; -} - -static int handle_battery_event(struct uevent *event) -{ - return 0; -} - -static int handle_block_event(struct uevent *event) -{ - char mediapath[255]; - media_t *media; - int n; - int maj, min; - blkdev_t *blkdev; - - /* - * Look for backing media for this block device - */ - if (!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'", get_uevent_param(event, "DEVTYPE")); - return -EINVAL; - } - - truncate_sysfs_path(event->path, n, mediapath, sizeof(mediapath)); - - if (!(media = media_lookup_by_path(mediapath, false))) { -#if DEBUG_UEVENT - LOG_VOL("No backend media found @ device path '%s'", mediapath); -#endif - return 0; - } - - maj = atoi(get_uevent_param(event, "MAJOR")); - min = atoi(get_uevent_param(event, "MINOR")); - - if (event->action == action_add) { - blkdev_t *disk; - - /* - * If there isn't a disk already its because *we* - * are the disk - */ - if (media->media_type == media_mmc) - disk = blkdev_lookup_by_devno(maj, ALIGN_MMC_MINOR(min)); - else - disk = blkdev_lookup_by_devno(maj, 0); - - if (!(blkdev = blkdev_create(disk, - event->path, - maj, - min, - media, - get_uevent_param(event, "DEVTYPE")))) { - LOGE("Unable to allocate new blkdev (%s)", strerror(errno)); - 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)", 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) { - if (rc == -EBUSY) { - LOGI("Volmgr not ready to handle device"); - } else { - LOGE("Volmgr failed to handle device (%d)", rc); - return rc; - } - } - } - } else if (event->action == action_remove) { - if (!(blkdev = blkdev_lookup_by_devno(maj, min))) - return 0; - - 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; - - 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", event->action); -#endif - } - return 0; -} - -static void _cb_blkdev_ok_to_destroy(blkdev_t *dev) -{ - media_t *media = media_lookup_by_dev(dev); - if (media) - media_remove_blkdev(media, dev); - blkdev_destroy(dev); -} - -static int handle_bdi_event(struct uevent *event) -{ - return 0; -} - -static int handle_mmc_event(struct uevent *event) -{ - if (event->action == action_add) { - media_t *media; - char serial[80]; - char *type; - - /* - * Pull card information from sysfs - */ - type = get_uevent_param(event, "MMC_TYPE"); - if (strcmp(type, "SD") && strcmp(type, "MMC")) - return 0; - - read_sysfs_var(serial, sizeof(serial), event->path, "serial"); - if (!(media = media_create(event->path, - get_uevent_param(event, "MMC_NAME"), - serial, - media_mmc))) { - LOGE("Unable to allocate new media (%s)", strerror(errno)); - return -1; - } - 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'", event->path); - return -1; - } - - LOGI("MMC card '%s' (serial %u) @ %s removed", media->name, - media->serial, media->devpath); - media_destroy(media); - } else { -#if DEBUG_UEVENT - LOG_VOL("No handler implemented for action %d", event->action); -#endif - } - - return 0; -} diff --git a/vold/uevent.h b/vold/uevent.h deleted file mode 100644 index 0e9e6716..00000000 --- a/vold/uevent.h +++ /dev/null @@ -1,21 +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. - */ - -#ifndef _UEVENT_MSG_H -#define _UEVENT_MSG_H - -#endif diff --git a/vold/ums.c b/vold/ums.c deleted file mode 100644 index 4d0fc259..00000000 --- a/vold/ums.c +++ /dev/null @@ -1,129 +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 <fcntl.h> -#include <errno.h> - -#include "vold.h" -#include "ums.h" - -#define DEBUG_UMS 0 - -static boolean host_connected = false; -static boolean ums_enabled = false; - -int ums_bootstrap(void) -{ - return 0; -} - -void ums_enabled_set(boolean enabled) -{ - ums_enabled = enabled; - send_msg(enabled ? VOLD_EVT_UMS_ENABLED : VOLD_EVT_UMS_DISABLED); -} - -boolean ums_enabled_get() -{ - return ums_enabled; -} - -void ums_hostconnected_set(boolean connected) -{ -#if DEBUG_UMS - LOG_VOL("ums_hostconnected_set(%d):", connected); -#endif - host_connected = connected; - - if (!connected) - ums_enabled_set(false); - send_msg(connected ? VOLD_EVT_UMS_CONNECTED : VOLD_EVT_UMS_DISCONNECTED); -} - -int ums_enable(char *dev_fspath, char *lun_syspath) -{ - LOG_VOL("ums_enable(%s, %s):", 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)", filename, strerror(errno)); - return -errno; - } - - if (write(fd, dev_fspath, strlen(dev_fspath)) < 0) { - LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); - close(fd); - return -errno; - } - - close(fd); - return 0; -} - -int ums_disable(char *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)", filename, strerror(errno)); - return -errno; - } - - char ch = 0; - - if (write(fd, &ch, 1) < 0) { - LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); - close(fd); - return -errno; - } - - close(fd); - return 0; -} - -boolean ums_hostconnected_get(void) -{ - return host_connected; -} - -int ums_send_status(void) -{ - int rc; - -#if DEBUG_UMS - LOG_VOL("ums_send_status():"); -#endif - - rc = send_msg(ums_enabled_get() ? VOLD_EVT_UMS_ENABLED : - VOLD_EVT_UMS_DISABLED); - if (rc < 0) - return rc; - - rc = send_msg(ums_hostconnected_get() ? VOLD_EVT_UMS_CONNECTED : - VOLD_EVT_UMS_DISCONNECTED); - - return rc; -} diff --git a/vold/ums.h b/vold/ums.h deleted file mode 100644 index 02cdec37..00000000 --- a/vold/ums.h +++ /dev/null @@ -1,31 +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. - */ - -#ifndef _UMS_H -#define _UMS_H - -// these must match the corresponding strings in java/android/android/os/UsbListener.java -#define VOLD_EVT_UMS_ENABLED "ums_enabled" -#define VOLD_EVT_UMS_DISABLED "ums_disabled" -#define VOLD_EVT_UMS_CONNECTED "ums_connected" -#define VOLD_EVT_UMS_DISCONNECTED "ums_disconnected" - - -int ums_send_status(void); -int ums_enable(char *device_file, char *lun_syspath); -int ums_disable(char *lun_syspath); -#endif diff --git a/vold/vold.c b/vold/vold.c deleted file mode 100644 index 11b99a9b..00000000 --- a/vold/vold.c +++ /dev/null @@ -1,238 +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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <pthread.h> - -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/un.h> - -#include <cutils/config_utils.h> -#include <cutils/cpu_info.h> -#include <cutils/properties.h> -#include <cutils/sockets.h> - -#include <linux/netlink.h> - -#include <private/android_filesystem_config.h> - -#include "vold.h" -#include "volmgr.h" - - -#define VOLD_SOCKET "vold" - -/* - * Globals - */ - -static int ver_major = 2; -static int ver_minor = 0; -static pthread_mutex_t write_mutex = PTHREAD_MUTEX_INITIALIZER; -static int fw_sock = -1; - -int bootstrap = 0; - -int main(int argc, char **argv) -{ - int door_sock = -1; - int uevent_sock = -1; - struct sockaddr_nl nladdr; - int uevent_sz = 64 * 1024; - - LOGI("Android Volume Daemon version %d.%d", ver_major, ver_minor); - - /* - * Create all the various sockets we'll need - */ - - // Socket to listen on for incomming framework connections - if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) { - LOGE("Obtaining file descriptor socket '%s' failed: %s", - VOLD_SOCKET, strerror(errno)); - exit(1); - } - - if (listen(door_sock, 4) < 0) { - LOGE("Unable to listen on fd '%d' for socket '%s': %s", - door_sock, VOLD_SOCKET, strerror(errno)); - exit(1); - } - - mkdir("/dev/block/vold", 0755); - - // Socket to listen on for uevent changes - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = getpid(); - nladdr.nl_groups = 0xffffffff; - - if ((uevent_sock = socket(PF_NETLINK, - SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { - LOGE("Unable to create uevent socket: %s", 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", strerror(errno)); - exit(1); - } - - if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { - LOGE("Unable to bind uevent socket: %s", strerror(errno)); - exit(1); - } - - /* - * Bootstrap - */ - - bootstrap = 1; - // Volume Manager - volmgr_bootstrap(); - - // SD Card system - mmc_bootstrap(); - - // USB Mass Storage - ums_bootstrap(); - - // Switch - switch_bootstrap(); - - bootstrap = 0; - /* - * Main loop - */ - LOG_VOL("Bootstrapping complete"); - while(1) { - fd_set read_fds; - struct timeval to; - int max = 0; - int rc = 0; - - to.tv_sec = (60 * 60); - to.tv_usec = 0; - - FD_ZERO(&read_fds); - FD_SET(door_sock, &read_fds); - if (door_sock > max) - max = door_sock; - FD_SET(uevent_sock, &read_fds); - if (uevent_sock > max) - max = uevent_sock; - - if (fw_sock != -1) { - FD_SET(fw_sock, &read_fds); - if (fw_sock > max) - max = fw_sock; - } - - if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) { - LOGE("select() failed (%s)", strerror(errno)); - sleep(1); - continue; - } - - if (!rc) { - continue; - } - - if (FD_ISSET(door_sock, &read_fds)) { - struct sockaddr addr; - socklen_t alen; - - alen = sizeof(addr); - - if (fw_sock != -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)", - strerror(errno)); - } - LOG_VOL("Accepted connection from framework"); - if ((rc = volmgr_send_states()) < 0) { - 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"); - close(fw_sock); - fw_sock = -1; - } else { - LOGE("Error processing framework command (%s)", - strerror(errno)); - } - } - } - - if (FD_ISSET(uevent_sock, &read_fds)) { - if ((rc = process_uevent_message(uevent_sock)) < 0) { - LOGE("Error processing uevent msg (%s)", strerror(errno)); - } - } - } // while - -} - -int send_msg(char* message) -{ - int result = -1; - - pthread_mutex_lock(&write_mutex); - -// LOG_VOL("send_msg(%s):", message); - - if (fw_sock >= 0) - result = write(fw_sock, message, strlen(message) + 1); - - pthread_mutex_unlock(&write_mutex); - - return result; -} - -int send_msg_with_data(char *message, char *data) -{ - int result = -1; - - char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1); - if (!buffer) { - LOGE("alloca failed in send_msg_with_data"); - return -1; - } - - strcpy(buffer, message); - strcat(buffer, data); - return send_msg(buffer); -} diff --git a/vold/vold.h b/vold/vold.h deleted file mode 100644 index abc27a18..00000000 --- a/vold/vold.h +++ /dev/null @@ -1,101 +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. - */ - -#ifndef VOLD_H__ -#define VOLD_H__ - -#define LOG_TAG "vold" -#include "cutils/log.h" - -typedef int boolean; -enum { - false = 0, - true = 1 -}; - -#define DEVPATH "/dev/block/" -#define DEVPATHLENGTH 11 - -#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) - -// Set this for logging error messages -#define ENABLE_LOG_ERROR - -// set this to log vold events -#define ENABLE_LOG_VOL - -#ifdef ENABLE_LOG_ERROR -#define LOG_ERROR(fmt, args...) \ - { LOGE(fmt , ## args); } -#else -#define LOG_ERROR(fmt, args...) \ - do { } while (0) -#endif /* ENABLE_LOG_ERROR */ - -#ifdef ENABLE_LOG_VOL -#define LOG_VOL(fmt, args...) \ - { LOGD(fmt , ## args); } -#else -#define LOG_VOL(fmt, args...) \ - do { } while (0) -#endif /* ENABLE_LOG_VOL */ - -#ifdef ENABLE_LOG_SERVER -#define LOG_SERVER(fmt, args...) \ - { LOGD(fmt , ## args); } -#else -#define LOG_SERVER(fmt, args...) \ - do { } while (0) -#endif /* ENABLE_LOG_SERVER */ - -#ifdef ENABLE_LOG_ASEC -#define LOG_ASEC(fmt, args...) \ - { LOGD(fmt , ## args); } -#else -#define LOG_ASEC(fmt, args...) \ - do { } while (0) -#endif /* ENABLE_LOG_ASEC */ - -/* - * Prototypes - */ - -int process_framework_command(int socket); - -int process_inotify_event(int fd); -int inotify_bootstrap(void); - -int process_uevent_message(int socket); -int simulate_uevent(char *subsystem, char *path, char *action, char **params); - -int mmc_bootstrap(void); -int ums_bootstrap(void); - -int volmgr_bootstrap(void); - -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, int buffer_size); -char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var); - -void ums_hostconnected_set(boolean connected); -boolean ums_hostconnected_get(void); - -int send_msg(char *msg); -int send_msg_with_data(char *msg, char *data); -extern int bootstrap; -#endif diff --git a/vold/volmgr.c b/vold/volmgr.c deleted file mode 100644 index deb680e0..00000000 --- a/vold/volmgr.c +++ /dev/null @@ -1,1247 +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 <sched.h> - -#include <sys/mount.h> - -#include <cutils/config_utils.h> -#include <cutils/properties.h> - -#include "vold.h" -#include "volmgr.h" -#include "blkdev.h" -#include "ums.h" -#include "format.h" -#include "devmapper.h" - -#include "volmgr_ext3.h" -#include "volmgr_vfat.h" - -#define DEBUG_VOLMGR 0 - -static volume_t *vol_root = NULL; -static boolean safe_mode = true; - -static struct volmgr_fstable_entry fs_table[] = { -// { "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 { - volume_state_t state; - char *event; - char *property_val; -}; - -static struct _volume_state_event_map volume_state_strings[] = { - { volstate_unknown, "volstate_unknown:", "unknown" }, - { volstate_nomedia, VOLD_EVT_NOMEDIA, VOLD_ES_PVAL_NOMEDIA }, - { volstate_unmounted, VOLD_EVT_UNMOUNTED, VOLD_ES_PVAL_UNMOUNTED }, - { volstate_checking, VOLD_EVT_CHECKING, VOLD_ES_PVAL_CHECKING }, - { volstate_mounted, VOLD_EVT_MOUNTED, VOLD_ES_PVAL_MOUNTED }, - { volstate_mounted_ro, VOLD_EVT_MOUNTED_RO, VOLD_ES_PVAL_MOUNTED_RO }, - { volstate_badremoval, VOLD_EVT_BADREMOVAL, VOLD_ES_PVAL_BADREMOVAL }, - { volstate_damaged, VOLD_EVT_DAMAGED, VOLD_ES_PVAL_DAMAGED }, - { volstate_nofs, VOLD_EVT_NOFS, VOLD_ES_PVAL_NOFS }, - { volstate_ums, VOLD_EVT_UMS, VOLD_ES_PVAL_UMS }, - { 0, NULL, NULL } -}; - - -static int volmgr_readconfig(char *cfg_path); -static int volmgr_config_volume(cnode *node); -static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy); -static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev); -static int _volmgr_start(volume_t *vol, blkdev_t *dev); -static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev); -static void *volmgr_start_fs_thread(void *arg); -static void volmgr_start_fs_thread_sighandler(int signo); -static void volume_setstate(volume_t *vol, volume_state_t state); -static char *conv_volstate_to_eventstr(volume_state_t state); -static char *conv_volstate_to_propstr(volume_state_t state); -static int volume_send_state(volume_t *vol); -static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg); -static int _volmgr_enable_ums(volume_t *); -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, 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"); - 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; -} - -int volmgr_send_states(void) -{ - volume_t *vol_scan = vol_root; - int rc; - - while (vol_scan) { - pthread_mutex_lock(&vol_scan->lock); - if ((rc = volume_send_state(vol_scan)) < 0) { - LOGE("Error sending state to framework (%d)", rc); - } - pthread_mutex_unlock(&vol_scan->lock); - vol_scan = vol_scan->next; - break; // XXX: - } - - return 0; -} - -/* - * Called when a block device is ready to be - * evaluated by the volume manager. - */ -int volmgr_consider_disk(blkdev_t *dev) -{ - volume_t *vol; - - if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true))) - 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; - - v = volmgr_lookup_volume_by_mountpoint(mount_point, true); - if (!v) - return -ENOENT; - - 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 -ENOENT; - } - - if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) { - LOGE("volmgr failed to start volume '%s'", v->mount_point); - } - } - - 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) -{ - int rc; - volume_t *v; - - v = volmgr_lookup_volume_by_mountpoint(mount_point, true); - if (!v) - return -ENOENT; - - if (v->state == volstate_mounted) - volmgr_send_eject_request(v); - - 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 *)) -{ - 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 - if (!(v = volmgr_lookup_volume_by_dev(dev))) { - if (cb) - cb(dev); - return 0; - } - - pthread_mutex_lock(&v->lock); - - 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); - - /* - * 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; - } - - } 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; - -#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 -} - -/* - * Instructs the volume manager to enable or disable USB mass storage - * on any volumes configured to use it. - */ -int volmgr_enable_ums(boolean enable) -{ - volume_t *v = vol_root; - - while(v) { - if (v->ums_path) { - int rc; - - if (enable) { - pthread_mutex_lock(&v->lock); - if (v->state == volstate_mounted) - volmgr_send_eject_request(v); - else if (v->state == volstate_ums || v->state == volstate_nomedia) { - pthread_mutex_unlock(&v->lock); - goto next_vol; - } - - // Stop the volume, and enable UMS in the callback - 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'", v->mount_point); - pthread_mutex_unlock(&v->lock); - continue; - } - - 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 %d:%d", - v->dev->disk->major, v->dev->disk->minor); - } - pthread_mutex_unlock(&v->lock); - } - } - next_vol: - v = v->next; - } - return 0; -} - -/* - * 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, %d:%d):", vol->mount_point, - dev->major, dev->minor); -#endif - - if (vol->state == volstate_unknown || - vol->state == volstate_mounted || - vol->state == volstate_mounted_ro) { - LOGE("Cannot consider volume '%s' because it is in state '%d", - vol->mount_point, vol->state); - return -EADDRINUSE; - } - - 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; - if (vol->media_type == media_mmc) - part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + 1); - else - part = blkdev_lookup_by_devno(dev->major, 1); - if (!part) { - if (vol->media_type == media_mmc) - part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor)); - else - 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; - } - - } - - 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, %d:%d) rc = %d", vol->mount_point, - dev->major, dev->minor, rc); -#endif - } else { - /* - * Device has multiple partitions - * This is where interesting partition policies could be implemented. - * For now just try them in sequence until one succeeds - */ - - rc = -ENODEV; - int i; - for (i = 0; i < dev->nr_parts; i++) { - blkdev_t *part; - if (vol->media_type == media_mmc) - part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + (i+1)); - else - part = blkdev_lookup_by_devno(dev->major, (i+1)); - if (!part) { - LOGE("Error - unable to lookup partition for blkdev %d:%d", - dev->major, dev->minor); - continue; - } - rc = _volmgr_start(vol, part); -#if DEBUG_VOLMGR - LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", - vol->mount_point, part->major, part->minor, rc); -#endif - if (!rc || rc == -EBUSY) - break; - } - - if (rc == -ENODEV) { - // Assert to make sure each partition had a backing blkdev - LOGE("Internal consistency error"); - return 0; - } - } - - if (rc == -ENODATA) { - LOGE("Device %d:%d contains no usable filesystems", - dev->major, dev->minor); - rc = 0; - } - - return rc; -} - -static void volmgr_reaper_thread_sighandler(int signo) -{ - LOGE("Volume reaper thread got signal %d", signo); -} - -static void __reaper_cleanup(void *arg) -{ - volume_t *vol = (volume_t *) arg; - - 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; - - // Wake up anyone that was waiting on this thread - pthread_mutex_unlock(&vol->worker_sem); - - // Unlock the volume - pthread_mutex_unlock(&vol->lock); -} - -static void *volmgr_reaper_thread(void *arg) -{ - volume_t *vol = (volume_t *) arg; - - pthread_cleanup_push(__reaper_cleanup, arg); - - vol->worker_running = true; - vol->worker_pid = getpid(); - - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = volmgr_reaper_thread_sighandler; - sigaction(SIGUSR1, &actions, NULL); - - 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); - 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; - } - sleep(1); - if (i >= 4) { - KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0); - if (!send_sig_kill) - send_sig_kill = true; - } - } - - if (!rc) { - LOGI("Reaper sucessfully unmounted %s", vol->mount_point); - vol->fs = NULL; - volume_setstate(vol, volstate_unmounted); - } else { - LOGE("Unable to unmount!! (%d)", rc); - } - - out: - pthread_cleanup_pop(1); - pthread_exit(NULL); - return NULL; -} - -// 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.."); - pthread_mutex_lock(&vol->worker_sem); - LOGI("Worker thread now available"); - } - - vol->worker_args.reaper_args.cb = cb; - vol->worker_args.reaper_args.cb_arg = arg; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol); -} - -static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange) -{ - int i, rc; - - if (v->state == volstate_mounted || v->state == volstate_badremoval) { - // Try to unmount right away (5 retries) - for (i = 0; i < 5; i++) { - rc = umount(v->mount_point); - if (!rc) - break; - - if (rc && (errno == EINVAL || errno == ENOENT)) { - rc = 0; - break; - } - - 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) { - 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; - } - - /* - * Since the volume is still in use, dispatch the stopping to - * a thread - */ - 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"); - pthread_kill(v->worker_thread, SIGUSR1); - } else - LOGE("Strange... we were in checking state but worker thread wasn't running.."); - goto out_cb_immed; - } - - out_cb_immed: - if (cb) - cb(v, arg); - return 0; -} - - -/* - * 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 *), boolean emit_statechange) -{ - 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; - -#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); - - 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); -} - -static int volmgr_readconfig(char *cfg_path) -{ - cnode *root = config_node("", ""); - cnode *node; - - config_load_file(root, cfg_path); - node = root->first_child; - - while (node) { - if (!strncmp(node->name, "volume_", 7)) - volmgr_config_volume(node); - else - 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, 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)); - - new->state = volstate_nomedia; - pthread_mutex_init(&new->lock, NULL); - pthread_mutex_init(&new->worker_sem, NULL); - - cnode *child = node->first_child; - - while (child) { - if (!strcmp(child->name, "media_path")) - 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'", child->value); - rc = -EINVAL; - goto out_free; - } - } else if (!strcmp(child->name, "mount_point")) - new->mount_point = strdup(child->value); - else if (!strcmp(child->name, "ums_path")) - new->ums_path = strdup(child->value); - else 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'", child->name); - child = child->next; - } - - 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) - vol_root = new; - else { - volume_t *scan = vol_root; - while (scan->next) - scan = scan->next; - 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 (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) - free(new->ums_path); - return rc; -} - -static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev) -{ - volume_t *scan = vol_root; - while(scan) { - if (scan->dev == dev) - return scan; - scan = scan->next; - } - return NULL; -} - -static volume_t *volmgr_lookup_volume_by_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; - int i; - - while (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 NULL; -} - -/* - * Attempt to bring a volume online - * Returns: 0 on success, errno on failure, with the following exceptions: - * - ENODATA - Unsupported filesystem type / blank - * vol->lock MUST be held! - */ -static int _volmgr_start(volume_t *vol, blkdev_t *dev) -{ - struct volmgr_fstable_entry *fs; - int rc = ENODATA; - -#if DEBUG_VOLMGR - LOG_VOL("_volmgr_start(%s, %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 %d:%d", dev->major, dev->minor); - volume_setstate(vol, volstate_nofs); - return -ENODATA; - } - - return volmgr_start_fs(fs, vol, dev); -} - -// vol->lock MUST be held! -static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev) -{ - /* - * Spawn a thread to do the actual checking / mounting in - */ - - if (vol->worker_running) { - LOGE("Worker thread is currently running.. waiting.."); - pthread_mutex_lock(&vol->worker_sem); - LOGI("Worker thread now available"); - } - - vol->dev = dev; - - if (bootstrap) { - LOGI("Aborting start of %s (bootstrap = %d)\n", vol->mount_point, - bootstrap); - vol->state = volstate_unmounted; - return -EBUSY; - } - - vol->worker_args.start_args.fs = fs; - vol->worker_args.start_args.dev = dev; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol); - - return 0; -} - -static void __start_fs_thread_lock_cleanup(void *arg) -{ - volume_t *vol = (volume_t *) arg; - -#if DEBUG_VOLMGR - LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point); -#endif - - vol->worker_running = false; - - // Wake up anyone that was waiting on this thread - pthread_mutex_unlock(&vol->worker_sem); - - // Unlock the volume - pthread_mutex_unlock(&vol->lock); -} - -static void *volmgr_start_fs_thread(void *arg) -{ - volume_t *vol = (volume_t *) arg; - - pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg); - pthread_mutex_lock(&vol->lock); - - vol->worker_running = true; - vol->worker_pid = getpid(); - - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = volmgr_start_fs_thread_sighandler; - sigaction(SIGUSR1, &actions, NULL); - - struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs; - blkdev_t *dev = vol->worker_args.start_args.dev; - int rc; - -#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) { -#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) { - LOGE("filesystem check aborted"); - goto out; - } - - if (rc < 0) { - 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; - } -#if DEBUG_VOLMGR - LOGI("%s filesystem check of %d:%d OK", fs->name, - dev->major, dev->minor); -#endif - } - - rc = fs->mount_fn(dev, vol, safe_mode); - if (!rc) { - 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 %d:%d failed (%d)", fs->name, dev->major, - dev->minor, rc); - - out_unmountable: - volume_setstate(vol, volstate_damaged); - out: - pthread_cleanup_pop(1); - pthread_exit(NULL); - return NULL; -} - -static void volmgr_start_fs_thread_sighandler(int signo) -{ - LOGE("Volume startup thread got signal %d", signo); -} - -static void volume_setstate(volume_t *vol, volume_state_t 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); - - if (prop_val) { - property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val); - volume_send_state(vol); - } -} - -static int volume_send_state(volume_t *vol) -{ - char *event = conv_volstate_to_eventstr(vol->state); - - return send_msg_with_data(event, vol->mount_point); -} - -static char *conv_volstate_to_eventstr(volume_state_t state) -{ - int i; - - for (i = 0; volume_state_strings[i].event != NULL; i++) { - if (volume_state_strings[i].state == state) - break; - } - - return volume_state_strings[i].event; -} - -static char *conv_volstate_to_propstr(volume_state_t state) -{ - int i; - - for (i = 0; volume_state_strings[i].event != NULL; i++) { - if (volume_state_strings[i].state == state) - break; - } - - return volume_state_strings[i].property_val; -} - diff --git a/vold/volmgr.h b/vold/volmgr.h deleted file mode 100644 index 2c7ec503..00000000 --- a/vold/volmgr.h +++ /dev/null @@ -1,135 +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. - */ - -#ifndef _VOLMGR_H -#define _VOLMGR_H - -#include <pthread.h> - -#include "vold.h" -#include "blkdev.h" -#include "media.h" -#include "devmapper.h" - -#define PROP_EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE" - -// these must match the corresponding states in the MediaState enum. -// A path to the volume mount point follows the colon -typedef enum volume_state { - volstate_unknown, - - volstate_nomedia, -#define VOLD_EVT_NOMEDIA "volume_nomedia:" -#define VOLD_ES_PVAL_NOMEDIA "removed" - - volstate_unmounted, -#define VOLD_EVT_UNMOUNTED "volume_unmounted:" -#define VOLD_ES_PVAL_UNMOUNTED "unmounted" - - volstate_checking, -#define VOLD_EVT_CHECKING "volume_checking:" -#define VOLD_ES_PVAL_CHECKING "checking" - - volstate_mounted, -#define VOLD_EVT_MOUNTED "volume_mounted:" -#define VOLD_ES_PVAL_MOUNTED "mounted" - - volstate_mounted_ro, -#define VOLD_EVT_MOUNTED_RO "volume_mounted_ro:" -#define VOLD_ES_PVAL_MOUNTED_RO "mounted_ro" - - volstate_badremoval, -#define VOLD_EVT_BADREMOVAL "volume_badremoval:" -#define VOLD_ES_PVAL_BADREMOVAL "bad_removal" - - volstate_damaged, -#define VOLD_EVT_DAMAGED "volume_damaged:" -#define VOLD_ES_PVAL_DAMAGED "unmountable" - - volstate_nofs, -#define VOLD_EVT_NOFS "volume_nofs:" -#define VOLD_ES_PVAL_NOFS "nofs" - - volstate_ums, -#define VOLD_EVT_UMS "volume_ums:" -#define VOLD_ES_PVAL_UMS "shared" - - volstate_ejecting, -#define VOLD_EVT_EJECTING "volume_ejecting:" -#define VOLD_ES_PVAL_EJECTING "ejecting" - - 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, boolean safe_mode); - boolean case_sensitive_paths; -}; - -struct volmgr_start_args { - struct volmgr_fstable_entry *fs; - 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_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; - 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; - -int volmgr_consider_disk(blkdev_t *dev); -int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *)); -int volmgr_send_states(void); -int volmgr_enable_ums(boolean enable); -int volmgr_stop_volume_by_mountpoint(char *mount_point); -int volmgr_start_volume_by_mountpoint(char *mount_point); -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 deleted file mode 100644 index fe3b2bb4..00000000 --- a/vold/volmgr_ext3.c +++ /dev/null @@ -1,184 +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 <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 - -static char E2FSCK_PATH[] = "/system/bin/e2fsck"; - -int ext_identify(blkdev_t *dev) -{ - 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 - free(devpath); - close(fd); - return rc; -} - -int ext_check(blkdev_t *dev) -{ - char *devpath; - -#if EXT_DEBUG - LOG_VOL("ext_check(%s):", dev->dev_fspath); -#endif - - 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, 1); - - 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 ext_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) -{ -#if EXT_DEBUG - LOG_VOL("ext_mount(%s, %s, %d):", dev->dev_fspath, vol->mount_point, safe_mode); -#endif - - 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 deleted file mode 100644 index bfe882a3..00000000 --- a/vold/volmgr_ext3.h +++ /dev/null @@ -1,27 +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. - */ - -#ifndef _VOLMGR_EXT3_H -#define _VOLMGR_EXT3_H - -#include "volmgr.h" -#include "blkdev.h" - -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 deleted file mode 100644 index 4c695e4e..00000000 --- a/vold/volmgr_vfat.c +++ /dev/null @@ -1,165 +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 <errno.h> - -#include <sys/mount.h> -#include <cutils/properties.h> - -#include "vold.h" -#include "volmgr.h" -#include "volmgr_vfat.h" -#include "logwrapper.h" - -#define VFAT_DEBUG 0 - -static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos"; - -int vfat_identify(blkdev_t *dev) -{ -#if VFAT_DEBUG - LOG_VOL("vfat_identify(%d:%d):", dev->major, dev->minor); -#endif - return 0; // XXX: Implement -} - -int vfat_check(blkdev_t *dev) -{ - int rc; - boolean rw = true; - -#if VFAT_DEBUG - LOG_VOL("vfat_check(%d:%d):", dev->major, dev->minor); -#endif - - if (access(FSCK_MSDOS_PATH, X_OK)) { - LOGE("vfat_check(%d:%d): %s not found (skipping checks)", - dev->major, dev->minor, FSCK_MSDOS_PATH); - return 0; - } - - int pass = 1; - do { - char *args[5]; - args[0] = FSCK_MSDOS_PATH; - args[1] = "-p"; - args[2] = "-f"; - args[3] = blkdev_get_devpath(dev); - args[4] = NULL; - rc = logwrap(4, args, 1); - free(args[3]); - - if (rc == 0) { - LOG_VOL("Filesystem check completed OK"); - return 0; - } else if (rc == 2) { - LOG_VOL("Filesystem check failed (not a FAT filesystem)"); - return -ENODATA; - } else if (rc == 4) { - if (pass++ <= 3) { - LOG_VOL("Filesystem modified - rechecking (pass %d)", - pass); - continue; - } else { - LOG_VOL("Failing check after too many rechecks"); - return -EIO; - } - } else if (rc == -11) { - LOG_VOL("Filesystem check crashed"); - return -EIO; - } else { - LOG_VOL("Filesystem check failed (unknown exit code %d)", rc); - return -EIO; - } - } while (0); - return 0; -} - -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(%d:%d, %s, %d):", dev->major, dev->minor, vol->mount_point, safe_mode); -#endif - - flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC; - - 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; - } - - /* - * Note: This is a temporary hack. If the sampling profiler is enabled, - * we make the SD card world-writable so any process can write snapshots. - * - * TODO: Remove this code once we have a drop box in system_server. - */ - char value[PROPERTY_VALUE_MAX]; - property_get("persist.sampling_profiler", value, ""); - if (value[0] == '1') { - LOGW("The SD card is world-writable because the" - " 'persist.sampling_profiler' system property is set to '1'."); - rc = mount(devpath, vol->mount_point, "vfat", flags, - "utf8,uid=1000,gid=1015,fmask=000,dmask=000,shortname=mixed"); - } else { - /* - * The mount masks restrict access so that: - * 1. The 'system' user cannot access the SD card at all - - * (protects system_server from grabbing file references) - * 2. Group users can RWX - * 3. Others can only RX - */ - rc = mount(devpath, vol->mount_point, "vfat", flags, - "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed"); - } - - if (rc && errno == EROFS) { - LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO", - dev->major, dev->minor, vol->mount_point); - flags |= MS_RDONLY; - rc = mount(devpath, vol->mount_point, "vfat", flags, - "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed"); - } - - if (rc == 0) { - char *lost_path; - asprintf(&lost_path, "%s/LOST.DIR", vol->mount_point); - if (access(lost_path, F_OK)) { - /* - * Create a LOST.DIR in the root so we have somewhere to put - * lost cluster chains (fsck_msdos doesn't currently do this) - */ - if (mkdir(lost_path, 0755)) { - LOGE("Unable to create LOST.DIR (%s)", strerror(errno)); - } - } - free(lost_path); - } - -#if VFAT_DEBUG - LOG_VOL("vfat_mount(%s, %d:%d): mount rc = %d", dev->major,k dev->minor, - vol->mount_point, rc); -#endif - free (devpath); - return rc; -} |
